import React from 'react'; import RcUpload from 'rc-upload'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import Dragger from './Dragger'; import UploadList from './UploadList'; import { UploadProps, UploadLocale } from './interface'; import { T, fileToObject, genPercentAdd, getFileItem, removeFileItem } from './utils'; export interface UploadContext { antLocale?: { Upload?: any, }; } const defaultLocale: UploadLocale = { uploading: '文件上传中', removeFile: '删除文件', uploadError: '上传错误', previewFile: '预览文件', }; export { UploadProps }; export default class Upload extends React.Component { static Dragger: typeof Dragger; static defaultProps = { prefixCls: 'ant-upload', type: 'select', multiple: false, action: '', data: {}, accept: '', beforeUpload: T, showUploadList: true, listType: 'text', // or pictrue className: '', disabled: false, supportServerRender: true, }; static contextTypes = { antLocale: PropTypes.object, }; context: UploadContext; recentUploadStatus: boolean | PromiseLike; progressTimer: any; refs: { [key: string]: any; upload: any; }; constructor(props) { super(props); this.state = { fileList: this.props.fileList || this.props.defaultFileList || [], dragState: 'drop', }; } componentWillUnmount() { this.clearProgressTimer(); } getLocale() { let locale = {}; if (this.context.antLocale && this.context.antLocale.Upload) { locale = this.context.antLocale.Upload; } return { ...defaultLocale, ...locale, ...this.props.locale, }; } onStart = (file) => { let targetItem; let nextFileList = this.state.fileList.concat(); if (file.length > 0) { targetItem = file.map(f => { const fileObject = fileToObject(f); fileObject.status = 'uploading'; return fileObject; }); nextFileList = nextFileList.concat(targetItem); } else { targetItem = fileToObject(file); targetItem.status = 'uploading'; nextFileList.push(targetItem); } this.onChange({ file: targetItem, fileList: nextFileList, }); // fix ie progress if (!(window as any).FormData) { this.autoUpdateProgress(0, targetItem); } } autoUpdateProgress(_, file) { const getPercent = genPercentAdd(); let curPercent = 0; this.clearProgressTimer(); this.progressTimer = setInterval(() => { curPercent = getPercent(curPercent); this.onProgress({ percent: curPercent, }, file); }, 200); } onSuccess = (response, file) => { this.clearProgressTimer(); try { if (typeof response === 'string') { response = JSON.parse(response); } } catch (e) { /* do nothing */ } let fileList = this.state.fileList; let targetItem = getFileItem(file, fileList); // removed if (!targetItem) { return; } targetItem.status = 'done'; targetItem.response = response; this.onChange({ file: { ...targetItem }, fileList, }); } onProgress = (e, file) => { let fileList = this.state.fileList; let targetItem = getFileItem(file, fileList); // removed if (!targetItem) { return; } targetItem.percent = e.percent; this.onChange({ event: e, file: { ...targetItem }, fileList: this.state.fileList, }); } onError = (error, response, file) => { this.clearProgressTimer(); let fileList = this.state.fileList; let targetItem = getFileItem(file, fileList); // removed if (!targetItem) { return; } targetItem.error = error; targetItem.response = response; targetItem.status = 'error'; this.onChange({ file: { ...targetItem }, fileList, }); } handleRemove(file) { const { onRemove } = this.props; Promise.resolve(typeof onRemove === 'function' ? onRemove(file) : onRemove).then(ret => { // Prevent removing file if (ret === false) { return; } const removedFileList = removeFileItem(file, this.state.fileList); if (removedFileList) { this.onChange({ file, fileList: removedFileList, }); } }); } handleManualRemove = (file) => { this.refs.upload.abort(file); file.status = 'removed'; // eslint-disable-line this.handleRemove(file); } onChange = (info) => { if (!('fileList' in this.props)) { this.setState({ fileList: info.fileList }); } const { onChange } = this.props; if (onChange) { onChange(info); } } componentWillReceiveProps(nextProps) { if ('fileList' in nextProps) { this.setState({ fileList: nextProps.fileList || [], }); } } onFileDrop = (e) => { this.setState({ dragState: e.type, }); } beforeUpload = (file, fileList) => { if (!this.props.beforeUpload) { return true; } const result = this.props.beforeUpload(file, fileList); if (result === false) { this.onChange({ file, fileList, }); return false; } else if (result && (result as PromiseLike).then) { return result; } return true; } clearProgressTimer() { clearInterval(this.progressTimer); } render() { const { prefixCls = '', showUploadList, listType, onPreview, type, disabled, children, className, } = this.props; const rcUploadProps = { onStart: this.onStart, onError: this.onError, onProgress: this.onProgress, onSuccess: this.onSuccess, ...this.props, beforeUpload: this.beforeUpload, }; delete rcUploadProps.className; const { showRemoveIcon, showPreviewIcon } = showUploadList as any; const uploadList = showUploadList ? ( ) : null; if (type === 'drag') { const dragCls = classNames(prefixCls, { [`${prefixCls}-drag`]: true, [`${prefixCls}-drag-uploading`]: this.state.fileList.some(file => file.status === 'uploading'), [`${prefixCls}-drag-hover`]: this.state.dragState === 'dragover', [`${prefixCls}-disabled`]: disabled, }); return (
{children}
{uploadList}
); } const uploadButtonCls = classNames(prefixCls, { [`${prefixCls}-select`]: true, [`${prefixCls}-select-${listType}`]: true, [`${prefixCls}-disabled`]: disabled, }); const uploadButton = (
); if (listType === 'picture-card') { return ( {uploadList} {uploadButton} ); } return ( {uploadButton} {uploadList} ); } }