# Upload

文件上传和拖拽上传。

可下载 [简易file server](/_file/file-server.zip) 启动本地的一个文件服务器。

将 `file-server` 解压到 `file-server`，进入该目录，直接依次执行 `install.bat` 和 `start.bat` 即可。

## Usage

> 服务端上传接口实现可以参考 [jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload/wiki)。

## 案例演示

### 基本使用

---demo
```js
import { Button, Upload, message, Icon } from 'amos-framework';

class Demo extends Component {
  render() {
    const props = {
      name: 'file',
      action: 'http://localhost:3100/file/upload',
      headers: {
        authorization: 'authorization-text'
      },
      onChange(info) {
        // start v1.9.11 版本新增
        if (info.method === 'onStart'){
          // start
          console.log('info.method', info.method);
        }

        if (info.file.status === 'uploading') {
          console.log(info.file, info.fileList);
        }else if (info.file.status === 'done') {
          message.success(`${info.file.name} file uploaded successfully`);
        } else if (info.file.status === 'error') {
          message.danger(`${info.file.name} file upload failed.`);
        }
      }
    };

    return (
      <Upload {...props}>
        <Button>
          <Icon icon="cloudupload"/> Click to Upload
        </Button>
      </Upload>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 设置默认已上传的文件列表

---demo
```js
import { Button, Upload, Icon } from 'amos-framework';

class Demo extends Component {
  render() {
    const props = {
      action: 'http://localhost:3100/file/upload',
      onChange({ file, fileList }) {
        if (file.status !== 'uploading') {
          console.log(file, fileList);
        }
      },
      defaultFileList: [
        {
          uid: 1,
          name: '4BBL3pw.png',
          status: 'done',
          reponse: 'Server Error 500', // custom error message to show
          url: 'https://i.imgur.com/4BBL3pw.jpg'
        },
        {
          uid: 2,
          name: 'ZkJIK8U.png',
          status: 'done',
          url: 'https://i.imgur.com/ZkJIK8U.jpg'
        },
        {
          uid: 3,
          name: 'NyCY9e7.png',
          status: 'error',
          reponse: 'Server Error 500', // custom error message to show
          url: 'https://i.imgur.com/NyCY9e7.jpg'
        }
      ]
    };

    return (
      <Upload {...props}>
        <Button>
          <Icon icon="upload" /> Upload
        </Button>
      </Upload>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 拖拽上传

---demo
```js
import { Upload, message, Icon } from 'amos-framework';

const Dragger = Upload.Dragger;

class Demo extends Component {
  render() {
    const props = {
      name: 'file',
      multiple: true,
      showUploadList: false,
      action: 'http://localhost:3100/file/upload',
      onChange(info) {
        const status = info.file.status;
        if (status !== 'uploading') {
          console.log(info.file, info.fileList);
        }
        if (status === 'done') {
          message.success(`${info.file.name} file uploaded successfully.`);
        } else if (status === 'error') {
          message.danger(`${info.file.name} file upload failed.`);
        }
      }
    };
    return (
      <div style={{ marginTop: 16, height: 180 }}>
        <Dragger {...props}>
          <p className="amos-upload-drag-icon">
            <Icon icon="inbox" />
          </p>
          <p className="amos-upload-text">点击选择文件，或者将文件拖到此处!</p>
        </Dragger>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 上传列表: 受控

---demo
```js
import { Button, Upload, Icon } from 'amos-framework';

class Demo extends Component {
  state = {
    fileList: [
      {
        uid: -1,
        name: '2fJiuD2.png',
        status: 'done',
        url: 'https://i.imgur.com/2fJiuD2.jpg'
      }
    ]
  };
  handleChange = info => {
    let fileList = info.fileList;

    // 1. Limit the number of uploaded files
    //    Only to show two recent uploaded files, and old ones will be replaced by the new
    fileList = fileList.slice(-2);

    // 2. read from response and show file link
    fileList = fileList.map(file => {
      if (file.response) {
        // Component will show file.url as link
        file.url = file.response.url;
      }
      return file;
    });

    // 3. filter successfully uploaded files according to response from server
    fileList = fileList.filter(file => {
      if (file.response) {
        return file.response.status === 'success';
      }
      return true;
    });

    this.setState({ fileList });
  };
  render() {
    const props = {
      action: 'http://localhost:3100/file/upload',
      onChange: this.handleChange,
      multiple: true
    };

    return (
      <Upload {...props} fileList={this.state.fileList}>
        <Button>
          <Icon icon="upload" /> upload
        </Button>
      </Upload>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 用户头像

使用 `beforeUpload` 用于过滤图片格式及其图片大小。

---demo
```js
import { Upload, message, Icon } from 'amos-framework';

function getBase64(img, callback) {
  const reader = new FileReader();
  reader.addEventListener('load', () => callback(reader.result));
  reader.readAsDataURL(img);
}

function beforeUpload(file) {
  const isJPG = file.type === 'image/jpeg';
  if (!isJPG) {
    message.danger('You can only upload JPG file!');
  }
  const isLt2M = file.size / 1024 / 1024 < 2;
  if (!isLt2M) {
    message.danger('Image must smaller than 2MB!');
  }
  return isJPG && isLt2M;
}

class Demo extends Component {
  state = {};

  handleChange = (info) => {
    if (info.file.status === 'done') {
      // Get this url from response in real world.
      getBase64(info.file.originFileObj, imageUrl => this.setState({ imageUrl }));
    }
  }

  render() {

    const imageUrl = this.state.imageUrl;
    return (
      <Upload
        className="avatar-uploader"
        name="avatar"
        showUploadList={false}
        action="http://localhost:3100/file/upload"
        beforeUpload={beforeUpload}
        onChange={this.handleChange}
      >
        {
          imageUrl ?
            <img src={imageUrl} alt="" className="avatar" /> :
            <Icon icon="plus" className="avatar-uploader-trigger" />
        }
      </Upload>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 照片墙

---demo
```js
import { Modal, Upload, Icon } from 'amos-framework';

class Demo extends Component {
  state = {
    previewVisible: false,
    previewImage: '',
    fileList: [
      {
        uid: -1,
        name: 'DMZdjMt.png',
        status: 'done',
        url: 'https://i.imgur.com/DMZdjMt.jpg'
      }
    ]
  };

  handleCancel = () => this.setState({ previewVisible: false });

  handlePreview = file => {
    this.setState({
      previewImage: file.url || file.thumbUrl,
      previewVisible: true
    });
  };

  handleChange = ({ fileList }) => this.setState({ fileList });

  render() {
    const { previewVisible, previewImage, fileList } = this.state;
    const uploadButton = (
      <div>
        <Icon icon="plus" />
        <div className="amos-upload-text">Upload</div>
      </div>
    );
    return (
      <div className="clearfix">
        <Upload
          action="http://localhost:3100/file/upload"
          listType="picture-card"
          fileList={fileList}
          onPreview={this.handlePreview}
          onChange={this.handleChange}
        >
          {fileList.length >= 3 ? null : uploadButton}
        </Upload>
        <Modal
          content={<img alt="example" style={{ width: '100%' }} src={previewImage} />}
          visible={previewVisible}
          noDefaultFooter
          onCancel={this.handleCancel}
        />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 图片列表样式

---demo
```js
import { Button, Upload, Icon } from 'amos-framework';

class Demo extends Component {
  render() {
    const fileList = [
      {
        uid: -1,
        name: 'VjqbQVL.jpg',
        status: 'done',
        url: 'https://i.imgur.com/VjqbQVL.jpg',
        thumbUrl: 'https://i.imgur.com/VjqbQVL.jpg'
      },
      {
        uid: -2,
        name: 'VTScsHK.jpg',
        status: 'done',
        url: 'https://i.imgur.com/VTScsHK.jpg',
        thumbUrl: 'https://i.imgur.com/VTScsHK.jpg'
      }
    ];

    const props = {
      action: 'http://localhost:3100/file/upload',
      listType: 'picture',
      defaultFileList: [...fileList]
    };

    const props2 = {
      action: 'http://localhost:3100/file/upload',
      listType: 'picture',
      defaultFileList: [...fileList],
      className: 'upload-list-inline'
    };
    return (
      <div>
        <Upload {...props}>
          <Button>
            <Icon icon="upload" /> upload
          </Button>
        </Upload>
        <br />
        <br />
        <Upload {...props2}>
          <Button>
            <Icon icon="upload" /> upload
          </Button>
        </Upload>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### beforeUpload 使用案例

使用 `beforeUpload` 实现上传前的过滤

---demo
```js
import { Button, Upload, Icon, message } from 'amos-framework';

class Demo extends Component {

  state = {
    fileList: [],
    uploading: false
  };

  beforeUpload = (file) => {
    this.setState(state => ({
      fileList: [...state.fileList, file]
    }));
    return false;
  }

  handleUpload = () => {
    const { fileList } = this.state;
    const formData = new FormData();
    fileList.forEach(file => {
      formData.append(file.name || file.uid, file);
    });

    this.setState({
      uploading: true,
    });

    // 上传文件
    fetch('http://localhost:3100/file/upload', {
      method: 'post',
      body: formData
    }).then(res => {
      if (res.ok){
        this.setState({
          fileList: [],
          uploading: false,
        });
        message.success('upload successfully.');
      } else {
        message.danger('upload failed.' + res.statusText);
      }
    }).catch(err => {
      this.setState({
        uploading: false,
      });
      message.danger('upload failed.');
    });
  };

  handleRemove = (file) => {
    this.setState(state => {
      const index = state.fileList.indexOf(file);
      const newFileList = state.fileList.slice();
      newFileList.splice(index, 1);
      return {
        fileList: newFileList
      };
    });
  }

  render() {
    const { uploading, fileList } = this.state;
    const props2 = {
      listType: 'picture',
      fileList,
      className: 'upload-list-inline',
      beforeUpload: this.beforeUpload,
      onRemove: this.handleRemove
    };
    return (
      <div>
        <Upload {...props2}>
          <Button>
            <Icon icon="upload" /> 选择文件
          </Button>
        </Upload>
        <Button onClick={this.handleUpload} disabled={fileList.length === 0} style={{ marginTop: 25 }}>
          {uploading ? '上传中...' : '开始上传'}
        </Button>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend


### beforeUpload 后端判断使用案例

使用 `beforeUpload` 实现上传前的过滤，返回值为 `promise`

---demo
```js
import { Button, Upload, Icon, message, Switch } from 'amos-framework';

class Demo extends Component {

  state = {
    fileList: [],
    uploading: false,
    auto: false
  };
  //
  beforeUpload = (file) => {
    this.setState(state => ({
      fileList: [...state.fileList, file]
    }));
    const name = this.state.auto ? 'yes' : 'no';
    return new Promise((resolve, reject) => {
      // 只有名称为 yes 的返回值中，result=true
      return fetch('http://localhost:3100/file/check/' + name).then(res => res.json()).then(data => {
        if (data.result){
          // 此处可以传入需要上传的 file
          // resolve(this.state.fileList);
          resolve();
        } else {
          // 需要手动上传
          reject();
        }
      }).catch(e => {
        reject();
      });
    });
  }

  // 手动上传，需要 beforeUpload 返回 false 或者 reject()
  handleUpload = () => {
    const { fileList } = this.state;
    const formData = new FormData();
    fileList.forEach(file => {
      formData.append(file.name || file.uid, file);
    });

    this.setState({
      uploading: true,
    });

    // 上传文件
    fetch('http://localhost:3100/file/upload', {
      method: 'post',
      body: formData
    }).then(res => {
      if (res.ok){
        this.setState({
          fileList: [],
          uploading: false,
        });
        message.success('upload successfully.');
      } else {
        message.danger('upload failed.' + res.statusText);
      }
    }).catch(err => {
      this.setState({
        uploading: false,
      });
      message.danger('upload failed.');
    });
  };

  handleRemove = (file) => {
    this.setState(state => {
      const index = state.fileList.indexOf(file);
      const newFileList = state.fileList.slice();
      newFileList.splice(index, 1);
      return {
        fileList: newFileList
      };
    });
  }

  render() {
    const { uploading, fileList, auto } = this.state;
    const props2 = {
      action: 'http://localhost:3100/file/upload',
      listType: 'picture',
      fileList,
      className: 'upload-list-inline',
      beforeUpload: this.beforeUpload,
      onRemove: this.handleRemove
    };
    return (
      <div>
        是否自动上传：<Switch onOff={auto} onLabel="是" offLabel="否" onChange={auto => this.setState({ auto })}/>
        <Upload {...props2}>
          <Button>
            <Icon icon="upload" /> 选择文件
          </Button>
        </Upload>
        <Button onClick={this.handleUpload} disabled={auto || fileList.length === 0} style={{ marginTop: 25 }}>
          {uploading ? '上传中...' : '开始上传'}
        </Button>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### beforeUpload 在弹出框中使用

在弹出框中，使用 `beforeUpload` 实现上传前的过滤，返回值为 `promise`。

注意：该示例只有设置自动上传为 true 时，才会触发 `onChange`

---demo
```js
import { Modal, Button, Upload, Icon, message, Switch } from 'amos-framework';

class Demo extends Component {

  state = {
    fileList: [],
    uploading: false,
    auto: false,
    visible: false
  };
  //
  beforeUpload = (file) => {
    this.setState(state => ({
      fileList: [...state.fileList, file]
    }));
    const name = this.state.auto ? 'yes' : 'no';
    return new Promise((resolve, reject) => {
      return fetch('http://localhost:3100/file/check/' + name).then(res => res.json()).then(data => {
        if (data.result){
          // 此处可以传入需要上传的 file
          // resolve(this.state.fileList);
          resolve();
        } else {
          // 需要手动上传
          reject();
        }
      }).catch(e => {
        reject();
      });
    });
  }

  // 手动上传，需要 beforeUpload 返回 false 或者 reject()
  handleUpload = () => {
    const { fileList } = this.state;
    const formData = new FormData();
    fileList.forEach(file => {
      formData.append(file.name || file.uid, file);
    });

    this.setState({
      uploading: true,
    });

    // 上传文件
    fetch('http://localhost:3100/file/upload', {
      method: 'post',
      body: formData
    }).then(res => {
      if (res.ok){
        this.setState({
          fileList: [],
          uploading: false,
        });
        message.success('upload successfully.');
      } else {
        message.danger('upload failed.' + res.statusText);
      }
    }).catch(err => {
      this.setState({
        uploading: false,
      });
      message.danger('upload failed.');
    });
  };

  handleRemove = (file) => {
    this.setState(state => {
      const index = state.fileList.indexOf(file);
      const newFileList = state.fileList.slice();
      newFileList.splice(index, 1);
      return {
        fileList: newFileList
      };
    });
  }

  handleChange = (...args) => {
    console.log(args);
  }

  open = () => {
    this.setState({
      visible: true
    });
  }

  cancel = () => {
    this.setState({
      visible: false
    });
  }

  renderContent() {
    const { uploading, fileList, auto } = this.state;
    const props2 = {
      action: 'http://localhost:3100/file/upload',
      listType: 'picture',
      fileList,
      className: 'upload-list-inline',
      beforeUpload: this.beforeUpload,
      onRemove: this.handleRemove,
      onChange: this.handleChange
    };
    return (
      <div>
        是否自动上传：<Switch onOff={auto} onLabel="是" offLabel="否" onChange={auto => this.setState({ auto })}/>
        <Upload {...props2}>
          <Button>
            <Icon icon="upload" /> 选择文件
          </Button>
        </Upload>
        <Button onClick={this.handleUpload} disabled={auto || fileList.length === 0} style={{ marginTop: 25 }}>
          {uploading ? '上传中...' : '开始上传'}
        </Button>
      </div>
    );
  }

  render() {
    const { visible } = this.state;
    return (
      <div>
        <Button onClick={this.open}>打开</Button>
        <Modal
          header="上传图片"
          visible={visible}
          onCancel={this.cancel}
          content={this.renderContent()}
        />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 上传 action 动态改变

在 `beforeUpload` 动态改变 action 地址。

---demo
```js
import { Modal, Button, Upload, Icon, message } from 'amos-framework';

class Demo extends Component {

  state = {
    fileList: [],
    auto: false,
    visible: false,
    actionId: undefined
  };

  //
  beforeUpload = (file) => {
    this.setState(state => ({
      fileList: [...state.fileList, file]
    }));
    return new Promise((resolve, reject) => {
      return fetch('http://localhost:3100/file/uuid').then(res => res.json()).then(data => {
        if (data.result){
          // resolve();
          this.setState({
            actionId: data.result
          }, () => {
            resolve();
          });
        } else {
          // 需要手动上传
          reject();
          this.manualUpload();
        }
      }).catch(e => {
        reject();
        this.manualUpload();
      });
    });
  }

  // 手动上传，如果 beforeUpload 返回 false 或者 reject()时，仍需上传，则需要执行以下手动上传方法
  manualUpload = () => {
    const { fileList } = this.state;
    const formData = new FormData();
    fileList.forEach(file => {
      formData.append(file.name || file.uid, file);
    });

    // 上传文件
    fetch('http://localhost:3100/file/upload/myfile', {
      method: 'post',
      body: formData
    }).then(res => {
      if (res.ok){
        this.setState({
          fileList: []
        });
        message.success('upload successfully.');
      } else {
        message.danger('upload failed.' + res.statusText);
      }
    }).catch(err => {
      message.danger('upload failed.');
    });
  };

  handleRemove = (file) => {
    this.setState(state => {
      const index = state.fileList.indexOf(file);
      const newFileList = state.fileList.slice();
      newFileList.splice(index, 1);
      return {
        fileList: newFileList
      };
    });
  }

  handleChange = (...args) => {
    console.log(args);
  }

  open = () => {
    this.setState({
      visible: true
    });
  }

  cancel = () => {
    this.setState({
      visible: false
    });
  }

  renderContent() {
    const { fileList, actionId } = this.state;
    const props2 = {
      action: `http://localhost:3100/file/upload/${actionId}`,
      listType: 'picture',
      fileList,
      className: 'upload-list-inline',
      beforeUpload: this.beforeUpload,
      onRemove: this.handleRemove,
      onChange: this.handleChange
    };
    return (
      <div>
        <Upload {...props2}>
          <Button>
            <Icon icon="upload" /> 选择文件
          </Button>
        </Upload>
      </div>
    );
  }

  render() {
    const { visible } = this.state;
    return (
      <div>
        <Button onClick={this.open}>打开</Button>
        <Modal
          header="上传图片"
          visible={visible}
          onCancel={this.cancel}
          content={this.renderContent()}
        />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

### 综合使用

---demo
```js
import { UploadModal } from 'amos-framework';

class Demo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      visible: false,
      currentImg: '',
      fileList: [],
      baseURI: 'http://localhost:3100/'
    };
  }

  onImgSelectChange = (file = {}) => {
    this.setState({
      currentImg: file.name
    });
  }

  show = () => {
    this.setState({
      visible: true
    }, this.loadFileList);
  }

  handleCancel = () => {
    this.setState({
      visible: false,
      fileList: []
    });
  };

  handleOk = () => {
    this.setState({
      visible: false,
      fileList: []
    });
  };

  loadFileList = () => {
    const { baseURI } = this.state;
    fetch(`${baseURI}file/list`)
    .then(res => {
      return res.json();
    })
    .then(d => {
      this.setState({ fileList: d.dataList });
    });
  }

  handleUploaderChange = (info) => {
    if (info.file && info.file.response && info.file.response.result === 'SUCCESS') {
      this.loadFileList();
    }
  }

  formatImgUrl = (name) => {
    const { baseURI } = this.state;
    return `${baseURI}file/load/${name}`;
  };

  render() {
    const { baseURI, visible, fileList, currentImg } = this.state;
    const uploadProps = {
      action: `${baseURI}file/upload`,
      headers: {
        'X-Api-Key': null,
        'X-Access-Token': 'XXSFAJKJSFASAF'
      },
      accept: 'image/*',
      onChange: this.handleUploaderChange
    };

    return (
      <div>
        <div style={{ width: 200, height: 200 }}>
          <img width={200} height={200} src={this.formatImgUrl(currentImg)} alt="" />
        </div>
        <UploadModal
          title="上传图片"
          chooseTitle="选择图片"
          enableRemove
          visible={visible}
          fileList={fileList}
          formatImgUrl={this.formatImgUrl}
          onImgSelectChange={this.onImgSelectChange}
          currentImg={currentImg}
          uploadProps={uploadProps}
          openModal={this.show}
          onOk={this.handleOk}
          onCancel={this.handleCancel}
        />
      </div>
    );
  }
}

ReactDOM.render(<Demo />, _react_runner_);
```
---demoend

## Props

| params | type | default | description |
| --- | --- | --- | --- |
| accept | string | - | 接受上传的文件类型, 详见 [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept)  and [input file](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file)|
| action | `string or (file) => Promise` | - | 必选参数, 上传的地址 |
| beforeUpload | (file, fileList) => `boolean or Promise` | - | 上传文件之前的钩子，参数为上传的文件，若返回 `false` 则停止上传。支持返回一个 Promise 对象，Promise 对象 reject 时则停止上传，resolve 时开始上传。resolve 支持传入自定义文件。 **注意：IE9 不支持该方法**。 |
| customRequest | Function | - | 通过覆盖默认的上传行为，可以自定义自己的上传实现 |
| data | `object or (file) => object` | - | 上传所需参数或返回上传参数的方法 |
| defaultFileList | `object[]` | - | 默认已经上传的文件列表 |
| disabled | boolean | false | 是否禁用 |
| fileList | `object[]` | - | 已经上传的文件列表（受控) |
| headers | object | - | 设置上传的请求头部，IE10 以上有效 |
| listType | string | 'text' | 上传列表的内建样式，支持三种基本样式 `text`, `picture` 和 `picture-card` |
| multiple | boolean | false | 是否支持多选文件，`ie10+` 支持。开启后按住 ctrl 可选择多个文件。 |
| name | string | 'file' | 发到后台的文件参数名 |
| showUploadList | Boolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean } | true | 是否展示 uploadList, 可设为一个对象，用于单独设定 showPreviewIcon 和 showRemoveIcon |
| supportServerRender | boolean | false | 服务端渲染时需要打开这个 |
| withCredentials | boolean | false | 上传请求时是否携带 cookie |
| onChange | `Function: (evt: { event, file, fileList, method: String }) => {}` | - | 上传文件改变时的状态，详见 [onChange](#onChange) |
| onPreview | Function(file) | - | 点击文件链接或预览图标时的回调 |
| onRemove   | Function(file): `boolean or Promise` | -   | 点击移除文件时的回调，返回值为 false 时不移除。支持返回一个 Promise 对象，Promise 对象 resolve(false) 或 reject 时不移除。               |

> 注意，如果 beforeUpload 中返回的 Promise 对象 reject 话，此时将无法完成自动上传，那么，默认的 `onChange` 事件则无法执行，why?
> onChange 为上传文件状态改变时的回调，既然 reject 了，此时就是手动上传，那么上传的中间过程也需要自行处理。
> 如果 Promise 没有正确处理，或者异常内部抛出而未执行 reject，均是不会自动上传，此时的手动上传文件，如果需要监听 onChange， 也需要自行处理。

### onChange

> 上传中、完成、失败都会调用这个函数。

文件状态改变的回调，返回为：

```js
{
  file: { /* ... */ },
  fileList: [ /* ... */ ],
  event: { /* ... */ },
  method: 'onStart|onProgress|onSuccess|onError|onRemove' // v1.9.11 版本之后添加
}
```

1. `file` 当前操作的文件对象。

   ```js
   {
      uid: 'uid',      // 文件唯一标识，建议设置为负数，防止和内部产生的 id 冲突
      name: 'xx.png'   // 文件名
      status: 'done', // 状态有：uploading done error removed
      response: '{"status": "success"}', // 服务端响应内容
      linkProps: '{"download": "image"}', // 下载链接额外的 HTML 属性
   }
   ```

2. `fileList` 当前的文件列表。
3. `event` 上传中的服务端响应内容，包含了上传进度等信息，高级浏览器支持。
