From ecb4d8a51fc82c424713849e610099f6e94c8895 Mon Sep 17 00:00:00 2001 From: liaoxuezhi Date: Thu, 25 Jul 2019 15:57:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=85=E9=83=A8=E8=87=AA=E5=8A=A8=E8=BD=AC?= =?UTF-8?q?=20form-data=20=E5=A6=82=E6=9E=9C=E5=AD=98=E5=9C=A8=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/components/SchemaRender.jsx | 23 ------------------ src/renderers/Form/File.tsx | 1 + src/types.ts | 2 ++ src/utils/api.ts | 9 ++++++- src/utils/helper.ts | 35 ++++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 24 deletions(-) diff --git a/examples/components/SchemaRender.jsx b/examples/components/SchemaRender.jsx index e1d2c7a5..bd517d34 100644 --- a/examples/components/SchemaRender.jsx +++ b/examples/components/SchemaRender.jsx @@ -89,32 +89,9 @@ export default function(schema) { data, config }) => { - let hasFile = function(data) { - return Object.keys(data).some(key => { - let value = data[key]; - - return value instanceof File || Array.isArray(value) && value.length && value[0] instanceof File; - }); - } - if (data && data instanceof FormData) { // config.headers = config.headers || {}; // config.headers['Content-Type'] = 'multipart/form-data'; - } else if (hasFile(data)) { - const fd = new FormData(); - Object.keys(data).forEach(key => { - const value = data[key]; - - if (value instanceof File) { - fd.append(key, value, value.name); - } else if (Array.isArray(value) && value.length && value[0] instanceof File) { - value.forEach(value => fd.append(`${key}[]`, value, value.name)); - } else { - // todo 复杂对象还需要特殊处理。 - fd.append(key, value); - } - }); - data = fd; } else if (data && typeof data !== 'string' && !(data instanceof Blob) diff --git a/src/renderers/Form/File.tsx b/src/renderers/Form/File.tsx index e7fda181..54ed0a9a 100644 --- a/src/renderers/Form/File.tsx +++ b/src/renderers/Form/File.tsx @@ -638,6 +638,7 @@ export default class FileControl extends React.Component { className="text-danger pull-right" onClick={() => this.removeFile(file, key)} href="javascript:void 0" + data-tooltip="移除" > {stateTextMap && stateTextMap[file.state as string] || ''} diff --git a/src/types.ts b/src/types.ts index 8555ea00..2cdcb828 100644 --- a/src/types.ts +++ b/src/types.ts @@ -12,6 +12,8 @@ export interface ApiObject { adaptor?: (payload: object, response: fetcherResult, api: ApiObject) => any; requestAdaptor?: (api: ApiObject) => ApiObject; cache?: number; + qsOptions?: any; + dataType?: 'json' | 'form-data' }; export type ApiString = string; export type Api = ApiString | ApiObject; diff --git a/src/utils/api.ts b/src/utils/api.ts index b7b63036..819c23df 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -16,7 +16,9 @@ import qs from 'qs'; import { evalExpression } from './tpl'; import { isObject, - isObjectShallowModified + isObjectShallowModified, + hasFile, + object2formData } from './helper'; interface ApiCacheConfig extends ApiObject { @@ -121,6 +123,11 @@ function responseAdaptor(ret: fetcherResult) { export function wrapFetcher(fn: (config: fetcherConfig) => Promise): (api: Api, data: object, options?: object) => Promise { return function (api, data, options) { api = buildApi(api, data, options) as ApiObject; + + if (api.data && (hasFile(api.data) || api.dataType === 'form-data')) { + api.data = object2formData(api.data, api.qsOptions); + } + api.requestAdaptor && (api = api.requestAdaptor(api) || api); if (typeof api.cache === 'number' && api.cache > 0) { diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 5d460a5d..c1f3d87b 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -8,6 +8,7 @@ import { } from '../types'; import { evalExpression } from './tpl'; import { boundMethod } from 'autobind-decorator'; +import qs from 'qs'; // 方便取值的时候能够把上层的取到,但是获取的时候不会全部把所有的数据获取到。 export function createObject(superProps?: { [propName: string]: any }, props?: { [propName: string]: any }, properties?: any): object { @@ -657,4 +658,38 @@ export function sortArray(items:Array, field:string, dir: -1 | return ret * dir; }) +} + +// 只判断一层, 如果层级很深,form-data 也不好表达。 +export function hasFile(object:any):boolean { + return Object.keys(object).some(key => { + let value = object[key]; + + return value instanceof File || Array.isArray(value) && value.length && value[0] instanceof File; + }); +} + +export function object2formData(data:any, options:any = { + arrayForamt: 'brackets' +}):any { + let others:any = {}; + const fd = new FormData(); + Object.keys(data).forEach(key => { + const value = data[key]; + + if (value instanceof File) { + fd.append(key, value, value.name); + } else if (Array.isArray(value) && value.length && value[0] instanceof File) { + value.forEach(value => fd.append(`${key}[]`, value, value.name)); + } else { + others[key] = value; + } + }); + + // 因为 key 的格式太多了,偷个懒,用 qs 来处理吧。 + qs.stringify(others, options).split('&').forEach(item => { + let parts = item.split('='); + parts[0] && fd.append(parts[0], parts[1]); + }); + return fd; } \ No newline at end of file