jc-biz-components
Version:
jc component library based on Antd
346 lines (313 loc) • 8.45 kB
JavaScript
import React from 'react'
import RcUpload from 'rc-upload'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import UploadList from './UploadList'
// import { Icon } from 'antd'
// import './style'
import { beforeUpload, onPreview, fileToObject, genPercentAdd, getFileItem, removeFileItem, changeIndex } from './utils'
const defaultLocale = {
uploading: '文件上传中',
removeFile: '删除文件',
uploadError: '上传错误',
previewFile: '预览文件',
}
export default class Upload extends React.Component {
static defaultProps = {
prefixCls: 'ant-upload',
type: 'select',
multiple: false,
action: '',
data: {},
accept: '',
beforeUpload: beforeUpload,
onPreview: onPreview,
showUploadList: true,
listType: 'text', // or pictrue
className: '',
disabled: false,
supportServerRender: true,
needOrder: false,
max: 999999,
itemStyle: {}
}
static contextTypes = {
antLocale: PropTypes.object,
}
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, isReUpload, index) => {
let targetItem = null
let nextFileList = this.state.fileList.concat()
if (isReUpload) {
targetItem = fileToObject(file)
targetItem.status = 'uploading'
const { fileList } = this.state
fileList.splice(index, 1, targetItem)
nextFileList = fileList
} else {
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).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) {
return false
} else if (result && (result).then) {
return result
}
return true
}
clearProgressTimer() {
clearInterval(this.progressTimer)
}
_orderChange = (file, value) => {
const modifyFileList = changeIndex(file, this.state.fileList, value)
this.onChange({
fileList: modifyFileList
})
}
render() {
const {
prefixCls = '', showUploadList, listType, onPreview,
type, disabled, children, className, needOrder
} = 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
const uploadList = showUploadList ? (
<UploadList
listType={listType}
items={this.state.fileList}
onPreview={onPreview}
onRemove={this.handleManualRemove}
showRemoveIcon={showRemoveIcon}
showPreviewIcon={showPreviewIcon}
locale={this.getLocale()}
orderChange={this._orderChange}
needOrder={needOrder}
reUploadRender={index => {
// return (
// <RcUpload {...rcUploadProps} onStart={(file) => this.onStart(file, true, index)} ref='upload'>
// <Icon type='reload' />
// </RcUpload>
// )
return null
}}
itemStyle={this.props.itemStyle}
/>
) : 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 (
<span className={className}>
<div
className={dragCls}
onDrop={this.onFileDrop}
onDragOver={this.onFileDrop}
onDragLeave={this.onFileDrop}
>
<RcUpload
{...rcUploadProps}
ref='upload'
className={`${prefixCls}-btn`}
>
<div className={`${prefixCls}-drag-container`}>
{children}
</div>
</RcUpload>
</div>
{uploadList}
</span>
)
}
const uploadButtonCls = classNames(prefixCls, {
[`${prefixCls}-select`]: true,
[`${prefixCls}-select-${listType}`]: true,
[`${prefixCls}-disabled`]: disabled,
})
const uploadButton = (
<div
className={uploadButtonCls}
style={{ display: (this.state.fileList.length < this.props.max) && children ? '' : 'none' }}
>
<RcUpload
{...rcUploadProps}
ref='upload'
/>
</div>
)
if (listType === 'picture-card') {
return (
<span className={className}>
{uploadList}
{!children && (<div style={{ clear: 'both' }} />)}
{uploadButton}
</span>
)
}
return (
<span className={className}>
{uploadButton}
{uploadList}
</span>
)
}
}