内部自动转 form-data 如果存在文件

This commit is contained in:
liaoxuezhi 2019-07-25 15:57:05 +08:00
parent a69b8211f4
commit ecb4d8a51f
5 changed files with 46 additions and 24 deletions

View File

@ -89,32 +89,9 @@ export default function(schema) {
data, data,
config 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) { if (data && data instanceof FormData) {
// config.headers = config.headers || {}; // config.headers = config.headers || {};
// config.headers['Content-Type'] = 'multipart/form-data'; // 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 } else if (data
&& typeof data !== 'string' && typeof data !== 'string'
&& !(data instanceof Blob) && !(data instanceof Blob)

View File

@ -638,6 +638,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
className="text-danger pull-right" className="text-danger pull-right"
onClick={() => this.removeFile(file, key)} onClick={() => this.removeFile(file, key)}
href="javascript:void 0" href="javascript:void 0"
data-tooltip="移除"
><i className="fa fa-times" /></a> ><i className="fa fa-times" /></a>
<span className="pull-right text-muted text-xs m-r-sm">{stateTextMap && stateTextMap[file.state as string] || ''}</span> <span className="pull-right text-muted text-xs m-r-sm">{stateTextMap && stateTextMap[file.state as string] || ''}</span>
<i className="fa fa-file fa-fw m-r-xs" /> <i className="fa fa-file fa-fw m-r-xs" />

View File

@ -12,6 +12,8 @@ export interface ApiObject {
adaptor?: (payload: object, response: fetcherResult, api: ApiObject) => any; adaptor?: (payload: object, response: fetcherResult, api: ApiObject) => any;
requestAdaptor?: (api: ApiObject) => ApiObject; requestAdaptor?: (api: ApiObject) => ApiObject;
cache?: number; cache?: number;
qsOptions?: any;
dataType?: 'json' | 'form-data'
}; };
export type ApiString = string; export type ApiString = string;
export type Api = ApiString | ApiObject; export type Api = ApiString | ApiObject;

View File

@ -16,7 +16,9 @@ import qs from 'qs';
import { evalExpression } from './tpl'; import { evalExpression } from './tpl';
import { import {
isObject, isObject,
isObjectShallowModified isObjectShallowModified,
hasFile,
object2formData
} from './helper'; } from './helper';
interface ApiCacheConfig extends ApiObject { interface ApiCacheConfig extends ApiObject {
@ -121,6 +123,11 @@ function responseAdaptor(ret: fetcherResult) {
export function wrapFetcher(fn: (config: fetcherConfig) => Promise<fetcherResult>): (api: Api, data: object, options?: object) => Promise<Payload | void> { export function wrapFetcher(fn: (config: fetcherConfig) => Promise<fetcherResult>): (api: Api, data: object, options?: object) => Promise<Payload | void> {
return function (api, data, options) { return function (api, data, options) {
api = buildApi(api, data, options) as ApiObject; 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); api.requestAdaptor && (api = api.requestAdaptor(api) || api);
if (typeof api.cache === 'number' && api.cache > 0) { if (typeof api.cache === 'number' && api.cache > 0) {

View File

@ -8,6 +8,7 @@ import {
} from '../types'; } from '../types';
import { evalExpression } from './tpl'; import { evalExpression } from './tpl';
import { boundMethod } from 'autobind-decorator'; import { boundMethod } from 'autobind-decorator';
import qs from 'qs';
// 方便取值的时候能够把上层的取到,但是获取的时候不会全部把所有的数据获取到。 // 方便取值的时候能够把上层的取到,但是获取的时候不会全部把所有的数据获取到。
export function createObject(superProps?: { [propName: string]: any }, props?: { [propName: string]: any }, properties?: any): object { export function createObject(superProps?: { [propName: string]: any }, props?: { [propName: string]: any }, properties?: any): object {
@ -657,4 +658,38 @@ export function sortArray<T extends any>(items:Array<T>, field:string, dir: -1 |
return ret * dir; 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;
} }