mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 20:09:08 +08:00
File 支持 功能
This commit is contained in:
parent
7cd10dc0f9
commit
a69b8211f4
@ -1,6 +1,6 @@
|
||||
### File
|
||||
|
||||
文件输入,amis 也默认处理了图片存储,提交给 API 的是文件的下载地址。
|
||||
用来负责文件上传,文件上传成功后会返回文件地址,这个文件地址会作为这个表单项的值,整个表单提交的时候,其实提交的是文件地址,文件上传已经在这个控件中完成了。
|
||||
|
||||
- `type` 请设置成 `file`
|
||||
- `reciever` 默认 `/api/upload/file` 如果想自己存储,请设置此选项。(PS: 如果想存自己的 bos, 系统配置中可以直接填写自己的 bos 配置。)
|
||||
@ -29,3 +29,5 @@
|
||||
"maxSize": 1048576
|
||||
}
|
||||
```
|
||||
|
||||
如果不希望 File 控件接管上传,可以配置 `asBlob` 或者 `asBase64` 这两个属性(二选一),采用这种方式后,File 控件不再自己上传了,而是直接把文件数据作为表单项的值,文件内容会在 Form 表单提交的接口里面一起带上。
|
@ -89,9 +89,32 @@ 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)
|
||||
|
@ -11,6 +11,7 @@ import {mapLimit} from 'async';
|
||||
import ImageControl from './Image';
|
||||
import {Payload} from '../../types';
|
||||
import { filter } from '../../utils/tpl';
|
||||
import Alert from '../../components/Alert2';
|
||||
|
||||
export interface FileProps extends FormControlProps {
|
||||
btnClassName: string;
|
||||
@ -43,19 +44,20 @@ export interface FileProps extends FormControlProps {
|
||||
[propName:string]: string;
|
||||
};
|
||||
asBase64?: boolean;
|
||||
asBlob?: boolean;
|
||||
resetValue?: string;
|
||||
};
|
||||
|
||||
export interface FileX extends File {
|
||||
state?: 'init' | 'error' | 'pending' | 'uploading' | 'uploaded' | 'invalid';
|
||||
state?: 'init' | 'error' | 'pending' | 'uploading' | 'uploaded' | 'invalid' | 'ready';
|
||||
}
|
||||
|
||||
export interface FileValue {
|
||||
filename?: string;
|
||||
value?:string;
|
||||
value?: any;
|
||||
name?: string;
|
||||
url?: string;
|
||||
state: 'init' | 'error' | 'pending' | 'uploading' | 'uploaded' | 'invalid';
|
||||
state: 'init' | 'error' | 'pending' | 'uploading' | 'uploaded' | 'invalid' | 'ready';
|
||||
[propName:string]: any;
|
||||
};
|
||||
|
||||
@ -93,7 +95,8 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
'pending': "等待上传",
|
||||
'uploading': "上传中",
|
||||
'error': "上传出错",
|
||||
'uploaded': "已上传"
|
||||
'uploaded': "已上传",
|
||||
"ready": ""
|
||||
},
|
||||
asBase64: false
|
||||
};
|
||||
@ -106,7 +109,12 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
let file:FileValue | FileX | undefined = files && typeof value === 'string'
|
||||
? find(files, item => (item as FileValue).value === value)
|
||||
: undefined;
|
||||
return value ? {
|
||||
return value ? value instanceof File ? {
|
||||
state: 'ready',
|
||||
value: value,
|
||||
name: value.name,
|
||||
url: ''
|
||||
} : {
|
||||
...(typeof value === 'string' ? {
|
||||
state: file && file.state ? file.state : 'init',
|
||||
value,
|
||||
@ -314,7 +322,8 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
startChunkApi,
|
||||
chunkApi,
|
||||
finishChunkApi,
|
||||
asBase64
|
||||
asBase64,
|
||||
asBlob
|
||||
} = this.props;
|
||||
|
||||
if (asBase64) {
|
||||
@ -322,14 +331,22 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => {
|
||||
cb(null, file, {
|
||||
value: reader.result,
|
||||
value: reader.result as string,
|
||||
name: file.name,
|
||||
url: '',
|
||||
state: 'uploaded'
|
||||
state: 'ready'
|
||||
});
|
||||
}
|
||||
reader.onerror = (error:any) => cb(error.message);
|
||||
return;
|
||||
} else if (asBlob) {
|
||||
setTimeout(() => cb(null, file, {
|
||||
name: file.name,
|
||||
value: file,
|
||||
url: '',
|
||||
state: 'ready'
|
||||
}), 4);
|
||||
return;
|
||||
}
|
||||
|
||||
let fn = useChunk === 'auto' && chunkSize && file.size > chunkSize || useChunk === true ? this.uploadBigFile : this.uploadFile;
|
||||
@ -384,17 +401,18 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
extractValue,
|
||||
valueField,
|
||||
delimiter,
|
||||
resetValue
|
||||
resetValue,
|
||||
asBlob
|
||||
} = this.props;
|
||||
|
||||
const files = this.state.files.filter(file => file.state == 'uploaded' || file.state == 'init');
|
||||
const files = this.state.files.filter(file => ~['uploaded', 'init', 'ready'].indexOf(file.state as string));
|
||||
let value:any = multiple ? files : files[0];
|
||||
|
||||
if (value) {
|
||||
if (joinValues) {
|
||||
value = Array.isArray(value) ? value.map((item: any) => item[valueField || 'value']).join(delimiter || ',') : value[valueField || 'value'];
|
||||
} else if (extractValue) {
|
||||
if (extractValue || asBlob) {
|
||||
value = Array.isArray(value) ? value.map((item: any) => item[valueField || 'value']) : value[valueField || 'value'];
|
||||
} else if (joinValues) {
|
||||
value = Array.isArray(value) ? value.map((item: any) => item[valueField || 'value']).join(delimiter || ',') : value[valueField || 'value'];
|
||||
}
|
||||
} else {
|
||||
value = typeof resetValue === 'undefined' ? '' : resetValue;
|
||||
@ -592,7 +610,9 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
autoUpload,
|
||||
stateTextMap,
|
||||
hideUploadButton,
|
||||
className
|
||||
className,
|
||||
asBlob,
|
||||
joinValues
|
||||
} = this.props;
|
||||
let {
|
||||
files,
|
||||
@ -605,10 +625,9 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
return (
|
||||
<div className={cx('amis-file-control', className)}>
|
||||
{error ? (
|
||||
<div>
|
||||
<p className="help-block text-danger inline">{error}</p>
|
||||
<a className="btn btn-link" onClick={this.clearError}><i className="fa fa-times" /></a>
|
||||
</div>
|
||||
<Alert level="danger" showCloseButton onClose={this.clearError}>
|
||||
{error}
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{files && files.length ? (
|
||||
@ -618,6 +637,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
<a
|
||||
className="text-danger pull-right"
|
||||
onClick={() => this.removeFile(file, key)}
|
||||
href="javascript:void 0"
|
||||
><i className="fa fa-times" /></a>
|
||||
<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" />
|
||||
|
Loading…
Reference in New Issue
Block a user