import * as React from 'react'; import cn from 'classnames'; import { I18nReceiver, II18nLocaleUpload } from '../i18n'; import AbstractUpload from './components/AbstractUpload'; import { ISingleUploadItemProps, ISingleUploadProps, IUploadChangeDetail, IUploadFileItem, IUploadTipConfig, } from './types'; import { formatFileSize } from './utils/format-file-size'; import { getTipsContent } from './utils/get-tips-content'; import { PartialRequired } from '../utils/types'; import { FILE_UPLOAD_STATUS } from './constants'; import { wrapPromise } from './utils/wrap-promise'; import SingleUploadTrigger from './components/single/Trigger'; import SingleUploadItem from './components/single/Item'; import { createBaseNewUploadFileItem } from './utils/create-new-upload-file-item'; interface ISingleUploadState { value: IUploadFileItem | null; } type ISingleUploadPropsInner = PartialRequired< ISingleUploadProps, 'maxSize' | 'manualUpload' >; export class SingleUpload extends AbstractUpload< IUploadFileItem, void, ISingleUploadItemProps, ISingleUploadProps, ISingleUploadState > { state: ISingleUploadState = { value: null, }; get isControlled() { return this.props.value !== undefined; } get value() { return this.isControlled ? this.props.value : this.state.value; } onChange = ( item: IUploadFileItem | null, detail?: IUploadChangeDetail, cb?: () => void ) => { const updateCallback = () => { this.props.onChange(item, detail); cb && cb(); }; if (this.isControlled) { updateCallback(); } else { this.setState( { value: item, }, updateCallback ); } }; getUploadItem(id: string): IUploadFileItem | null { return this.value?.id === id ? this.value : null; } /** * 更新某个上传项的属性 */ updateUploadItem = ( updateItemId: string, overrideProps: Partial ) => { const updateItem = this.getUploadItem(updateItemId); // 上传项已经不存在,不执行 update 操作 if (!updateItem) { return; } const newItem: IUploadFileItem = { ...updateItem, ...overrideProps, }; this.onChange(newItem, { item: newItem, type: 'change', }); }; createNewUploadFileItem(file: File): IUploadFileItem { return createBaseNewUploadFileItem(file); } deleteUploadItem = (deleteItem: IUploadFileItem) => { this.onChange(null, { item: deleteItem, type: 'delete', }); }; retryUploadItem = (retryItem: IUploadFileItem) => { const newRetryItem = { ...retryItem, status: FILE_UPLOAD_STATUS.uploading, percent: 0, }; this.onChange( newRetryItem, { item: newRetryItem, type: 'retry', }, () => this.emitOnUpload(retryItem.file, newRetryItem) ); }; onTriggerUploadFile = (file: File) => { const { beforeUpload } = this.props; const beforeUploadRes = wrapPromise( beforeUpload ? beforeUpload(file) : true ); // check is need upload return beforeUploadRes .then(() => { // create upload file item async return this.createNewUploadFileItem(file); }) .then(newUploadFileItem => { // update file list this.onChange( newUploadFileItem, { item: newUploadFileItem, type: 'add', }, () => this.emitOnUpload(file, newUploadFileItem) ); }); }; protected renderTips() { const { tips, maxSize } = this.props as ISingleUploadPropsInner; const config: IUploadTipConfig = { ...this.props, formattedMaxSize: formatFileSize(maxSize), }; const tipsContent = getTipsContent(tips, config); return ( tipsContent && (
{tipsContent}
) ); } protected renderTrigger(i18n: II18nLocaleUpload): React.ReactNode { const { accept, maxSize, disabled } = this.props as ISingleUploadPropsInner; return ( ); } renderItem(i18n: II18nLocaleUpload): React.ReactNode { const { customUploadItem } = this.props; const UploadItem = customUploadItem || SingleUploadItem; return ( ); } render() { const { className } = this.props; return ( {i18n => { return (
{this.value ? this.renderItem(i18n) : this.renderTrigger(i18n)} {this.renderTips()}
); }}
); } } export default SingleUpload;