| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { Upload, message, Button, Icon, Progress, notification } from 'antd' |
| | | import md5 from 'md5' |
| | | import Api from '@/api' |
| | | import './index.scss' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Upload, Button, Progress, notification } from 'antd' |
| | | import { UploadOutlined } from '@ant-design/icons' |
| | | |
| | | let service = window.GLOB.service ? (/\/$/.test(window.GLOB.service) ? window.GLOB.service : window.GLOB.service + '/') : '' |
| | | let Url = '/Upload' |
| | | if (process.env.NODE_ENV === 'production') { |
| | | Url = document.location.origin + '/' + service + 'zh-CN/Home/Upload' |
| | | } |
| | | import Api from '@/api' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import './index.scss' |
| | | |
| | | class FileUpload extends Component { |
| | | static propTpyes = { |
| | | value: PropTypes.array, // 按钮信息、表单列表 |
| | | maxFile: PropTypes.any, // 最大文件数 |
| | | fileType: PropTypes.string // 文件显示类型 |
| | | data: PropTypes.any, |
| | | config: PropTypes.object, |
| | | onChange: PropTypes.func, |
| | | } |
| | | |
| | | state = { |
| | | baseUrl: Url, |
| | | percent: 0, |
| | | showprogress: false |
| | | accept: '', |
| | | accepts: null, |
| | | maxFile: null, |
| | | rduri: '', |
| | | limit: 2, |
| | | compress: 'false', |
| | | fileType: 'text', |
| | | showprogress: false, |
| | | maxSize: 0, |
| | | filelist: [] |
| | | } |
| | | |
| | | init = async () => { |
| | | try { |
| | | const OSSData = await this.mockGetOSSData() |
| | | UNSAFE_componentWillMount () { |
| | | const { config, data } = this.props |
| | | |
| | | this.setState({ |
| | | OSSData |
| | | }) |
| | | } catch (error) { |
| | | message.error(error) |
| | | let filelist = [] |
| | | if (config.initval) { |
| | | if (/^data:image/.test(config.initval)) { |
| | | filelist = [{ |
| | | uid: '0', |
| | | name: 'data:image/jpeg;base64', |
| | | status: 'done', |
| | | url: config.initval, |
| | | origin: true |
| | | }] |
| | | } else { |
| | | try { |
| | | filelist = config.initval.split(',').map((url, index) => { |
| | | return { |
| | | uid: `${index}`, |
| | | name: url.slice(url.lastIndexOf('/') + 1), |
| | | status: 'done', |
| | | url: url, |
| | | origin: true |
| | | } |
| | | }) |
| | | } catch (e) { |
| | | filelist = [] |
| | | } |
| | | |
| | | if (data && config.subFields && config.subFields.length === 1 && filelist.length === 1) { |
| | | if (data[config.subFields[0].field]) { |
| | | filelist[0].name = data[config.subFields[0].field] |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | let accept = '' |
| | | let accepts = null |
| | | let compress = config.compress || 'false' |
| | | let maxFile = config.maxfile && config.maxfile > 0 ? config.maxfile : null |
| | | if (compress === 'true' || compress === 'base64') { |
| | | accepts = ['.jpg', '.png', '.gif', '.jpeg'] |
| | | accept = accepts.join(',') |
| | | if (compress === 'base64') { |
| | | maxFile = 1 |
| | | } |
| | | } else if (config.suffix) { |
| | | accepts = config.suffix.split(',').map(item => { |
| | | if (!/^\./ig.test(item)) { |
| | | item = '.' + item |
| | | } |
| | | return item |
| | | }) |
| | | accept = accepts.join(',') |
| | | } |
| | | let rduri = config.rduri || '' |
| | | |
| | | if (window.GLOB.systemType === 'production') { |
| | | rduri = config.proRduri || '' |
| | | } |
| | | |
| | | this.setState({ |
| | | rduri, |
| | | accept, |
| | | accepts, |
| | | filelist, |
| | | compress, |
| | | limit: config.limit || 2, |
| | | maxSize: config.maxSize || 0, |
| | | maxFile: maxFile, |
| | | fileType: config.fileType || 'text' |
| | | }) |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | return !is(fromJS(this.state), fromJS(nextState)) |
| | | } |
| | | |
| | | onChange = ({ fileList }) => { |
| | | const { onChange } = this.props |
| | | fileList = fileList.map(item => { |
| | | if (item.status === 'error' && /^<!DOCTYPE html>/.test(item.response)) { |
| | | item.response = '' |
| | | } |
| | | return item |
| | | }) |
| | | |
| | | if (onChange) { |
| | | onChange([...fileList]) |
| | | } |
| | | this.setState({filelist: fileList}) |
| | | } |
| | | |
| | | onRemove = file => { |
| | | const { value, onChange } = this.props |
| | | const files = this.state.filelist.filter(v => v.uid !== file.uid) |
| | | |
| | | const files = value.filter(v => v.url !== file.url) |
| | | this.setState({filelist: files}) |
| | | |
| | | if (onChange) { |
| | | onChange(files) |
| | | } |
| | | } |
| | | let vals = [] |
| | | |
| | | getExtraData = () => { |
| | | return { |
| | | RootPath: 'Content/images/upload/' |
| | | } |
| | | } |
| | | |
| | | shardupload = (file, shardSize, shardCount, i, fileList) => { |
| | | let start = i * shardSize |
| | | let end = Math.min(file.size, start + shardSize) |
| | | // let param = { |
| | | // file: file.slice(start, end), |
| | | // fileMd5: md5(''), |
| | | // shardingMd5: md5(''), |
| | | // baseDomain: '', |
| | | // rootPath: 'Content/images/upload/', |
| | | // fileName: file.name, |
| | | // fileExt: file.type.replace('image/', ''), |
| | | // shardingCnt: shardCount, |
| | | // shardingNo: i + 1 |
| | | // } |
| | | |
| | | let form = new FormData() |
| | | let pice = file.slice(start, end) |
| | | |
| | | form.append('file', pice) //slice方法用于切出文件的一部分 |
| | | form.append('fileMd5', md5(file)) |
| | | form.append('shardingMd5', md5(pice)) |
| | | form.append('baseDomain', '') |
| | | form.append('rootPath', 'Content/images/upload/') |
| | | form.append('fileName', file.name) |
| | | form.append('fileExt', file.type.replace('image/', '')) |
| | | form.append('shardingCnt', shardCount) |
| | | form.append('shardingNo', i + 1) |
| | | |
| | | Api.getLargeFileUpload(form).then(res => { |
| | | if (res.status) { |
| | | if (i < shardCount) { |
| | | i++ |
| | | |
| | | this.setState({ |
| | | percent: Math.floor(100 * (i / shardCount)) |
| | | }) |
| | | this.shardupload(file, shardSize, shardCount, i, fileList) |
| | | } |
| | | } else { |
| | | fileList = fileList.filter(item => !!item.url) |
| | | notification.warning({ |
| | | top: 92, |
| | | message: res.message, |
| | | duration: 5 |
| | | }) |
| | | files.forEach(item => { |
| | | if (item.origin && item.url) { |
| | | vals.push(item.url) |
| | | } else if (!item.origin && item.status === 'done' && item.response) { |
| | | vals.push(item.response) |
| | | } |
| | | }) |
| | | // } else { |
| | | // this.setState({ |
| | | // percent: 100 |
| | | // }, () => { |
| | | // setTimeout(() => { |
| | | // this.setState({ |
| | | // showprogress: false, |
| | | // percent: 0 |
| | | // }) |
| | | // }, 200) |
| | | // }) |
| | | // } |
| | | |
| | | this.props.onChange(vals.join(',')) |
| | | } |
| | | |
| | | beforeUpload = (file, fileList) => { |
| | | let shardSize = 2 * 1024 * 1024 |
| | | onUpdate = (url, file_name) => { |
| | | const { config } = this.props |
| | | |
| | | if (file.size > shardSize) { |
| | | // this.setState({ |
| | | // showprogress: true, |
| | | // percent: 0 |
| | | // }) |
| | | // let shardCount = Math.ceil(file.size / shardSize) |
| | | let filelist = fromJS(this.state.filelist).toJS() |
| | | |
| | | // this.shardupload(file, shardSize, shardCount, 0, fileList) |
| | | // return false |
| | | return true |
| | | } else { |
| | | return true |
| | | if (filelist[filelist.length -1]) { |
| | | filelist[filelist.length -1].status = 'done' |
| | | filelist[filelist.length -1].response = url |
| | | filelist[filelist.length -1].origin = false |
| | | } |
| | | |
| | | filelist = filelist.filter(item => !!(item.url || item.response)) |
| | | |
| | | let vals = [] |
| | | |
| | | filelist.forEach(item => { |
| | | if (item.origin && item.url) { |
| | | vals.push(item.url) |
| | | } else if (!item.origin && item.status === 'done' && item.response) { |
| | | vals.push(item.response) |
| | | } |
| | | }) |
| | | |
| | | this.setState({filelist}) |
| | | |
| | | if (config.subFields && file_name) { |
| | | let other = {} |
| | | config.subFields.forEach((n, i) => { |
| | | other[n.field] = file_name |
| | | setTimeout(() => { |
| | | MKEmitter.emit('mkFC', 'input', n.uuid, file_name) |
| | | }, i * 5) |
| | | }) |
| | | |
| | | this.props.onChange(vals.join(','), other) |
| | | } else { |
| | | this.props.onChange(vals.join(',')) |
| | | } |
| | | } |
| | | |
| | | onFail = (msg) => { |
| | | let filelist = this.state.filelist.map(item => { |
| | | if (!item.url && !item.response && !item.status) { |
| | | item.status = 'error' |
| | | } |
| | | return item |
| | | }) |
| | | |
| | | this.setState({filelist, showprogress: false, percent: 0}) |
| | | |
| | | notification.warning({ |
| | | top: 92, |
| | | message: msg || '文件上传失败!', |
| | | duration: 5 |
| | | }) |
| | | } |
| | | |
| | | getuuid = () => { |
| | | let uuid = [] |
| | | let _options = '0123456789abcdefghigklmnopqrstuv' |
| | | for (let i = 0; i < 19; i++) { |
| | | uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1)) |
| | | } |
| | | uuid = uuid.join('') |
| | | return uuid |
| | | } |
| | | |
| | | beforeUpload = (file) => { |
| | | const { accepts, compress, limit, rduri, maxSize } = this.state |
| | | |
| | | if (accepts && file.name) { |
| | | let pass = false |
| | | accepts.forEach(type => { |
| | | if (new RegExp(type + '$', 'ig').test(file.name)) { |
| | | pass = true |
| | | } |
| | | }) |
| | | |
| | | if (!pass) { |
| | | setTimeout(() => { |
| | | this.onFail('文件格式错误!') |
| | | }, 10) |
| | | return false |
| | | } |
| | | } |
| | | if (maxSize) { |
| | | let fileSize = file.size / 1024 / 1024 |
| | | |
| | | if (fileSize > maxSize) { |
| | | setTimeout(() => { |
| | | this.onFail(`文件大小不可超过${maxSize}M`) |
| | | }, 10) |
| | | return false |
| | | } |
| | | } |
| | | |
| | | this.setState({ |
| | | showprogress: true, |
| | | percent: 0 |
| | | }) |
| | | |
| | | let file_name = file.name |
| | | |
| | | if (compress === 'true' || compress === 'base64') { |
| | | let reader = new FileReader() |
| | | let fileSize = file.size / 1024 / 1024 |
| | | let compressRate = 0.9 |
| | | |
| | | if (fileSize / limit > 5) { |
| | | compressRate = 0.4 |
| | | } else if (fileSize / limit > 4) { |
| | | compressRate = 0.5 |
| | | } else if (fileSize / limit > 3) { |
| | | compressRate = 0.6 |
| | | } else if (fileSize / limit > 2) { |
| | | compressRate = 0.7 |
| | | } else if (fileSize > limit) { |
| | | compressRate = 0.8 |
| | | } |
| | | |
| | | reader.onload = (e) => { |
| | | let img = new Image() |
| | | let maxW = 640 |
| | | |
| | | img.onload = () => { |
| | | let cvs = document.createElement( 'canvas') |
| | | let ctx = cvs.getContext( '2d') |
| | | |
| | | if (img.width > maxW) { |
| | | img.height *= maxW / img.width |
| | | img.width = maxW |
| | | } |
| | | |
| | | cvs.width = img.width |
| | | cvs.height = img.height |
| | | |
| | | ctx.clearRect(0, 0, cvs.width, cvs.height) |
| | | ctx.drawImage(img, 0, 0, img.width, img.height) |
| | | |
| | | let param = {Base64Img: cvs.toDataURL('image/jpeg', compressRate)} |
| | | |
| | | if (this.props.config.compress === 'base64') { |
| | | this.onUpdate(param.Base64Img, file_name) |
| | | |
| | | this.setState({ |
| | | percent: 100 |
| | | }, () => { |
| | | setTimeout(() => { |
| | | this.setState({ |
| | | showprogress: false, |
| | | percent: 0 |
| | | }) |
| | | }, 200) |
| | | }) |
| | | } else { |
| | | if (rduri) { |
| | | param.rduri = rduri |
| | | } |
| | | |
| | | Api.fileuploadbase64(param).then(result => { |
| | | if (result.status && result.Images) { |
| | | let url = window.GLOB.baseurl + result.Images |
| | | |
| | | if (rduri) { |
| | | url = rduri.replace(/webapi(.*)$/, '') + result.Images |
| | | } |
| | | |
| | | this.onUpdate(url, file_name) |
| | | |
| | | this.setState({ |
| | | percent: 100 |
| | | }, () => { |
| | | setTimeout(() => { |
| | | this.setState({ |
| | | showprogress: false, |
| | | percent: 0 |
| | | }) |
| | | }, 200) |
| | | }) |
| | | } else { |
| | | this.onFail(result.message) |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | |
| | | img.onerror = () => { |
| | | this.onFail('图片读取失败!') |
| | | } |
| | | |
| | | img.src = e.target.result |
| | | } |
| | | |
| | | reader.onerror = () => { |
| | | this.onFail('文件读取失败!') |
| | | } |
| | | |
| | | reader.readAsDataURL(file) |
| | | return false |
| | | } else if (compress === 'oss') { |
| | | let _param = new FormData() |
| | | _param.append('multipartFile', file) |
| | | _param.append('userId', sessionStorage.getItem('UserID') || '') |
| | | |
| | | Api.fileOssUpload(_param).then(res => { |
| | | if (res.status) { |
| | | if (res.urlPath) { |
| | | let path = (/^\/\//.test(res.urlPath) ? 'https:' : '') + res.urlPath |
| | | this.onUpdate(path, file_name) |
| | | this.setState({ |
| | | percent: 100 |
| | | }, () => { |
| | | setTimeout(() => { |
| | | this.setState({ |
| | | showprogress: false, |
| | | percent: 0 |
| | | }) |
| | | }, 200) |
| | | }) |
| | | } else { |
| | | this.onFail('文件上传失败!') |
| | | } |
| | | } else { |
| | | this.onFail(res.message || '文件上传失败!') |
| | | } |
| | | }) |
| | | |
| | | return false |
| | | } |
| | | |
| | | let form = new FormData() |
| | | |
| | | form.append('file', file) |
| | | |
| | | Api.getFileUpload(form).then(res => { |
| | | if (res.status) { |
| | | if (res.urlPath) { |
| | | this.onUpdate(res.urlPath, file_name) |
| | | } else { |
| | | this.onFail() |
| | | } |
| | | this.setState({ |
| | | percent: 100 |
| | | }, () => { |
| | | setTimeout(() => { |
| | | this.setState({ |
| | | showprogress: false, |
| | | percent: 0 |
| | | }) |
| | | }, 200) |
| | | }) |
| | | } else { |
| | | this.onFail(res.message) |
| | | } |
| | | }) |
| | | |
| | | return false |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | render() { |
| | | const { value, maxFile, fileType } = this.props |
| | | const { showprogress, percent, baseUrl } = this.state |
| | | const { showprogress, percent, filelist, maxFile, fileType, accept } = this.state |
| | | |
| | | let uploadable = '' |
| | | let uploadable = 'fileupload-form-container ' |
| | | |
| | | if (maxFile && maxFile > 0 && value && value.length >= maxFile) { |
| | | uploadable = 'limit-fileupload' |
| | | if (maxFile && filelist.length >= maxFile) { |
| | | uploadable += 'limit-fileupload' |
| | | } |
| | | |
| | | const props = { |
| | | name: 'file', |
| | | disabled: showprogress, |
| | | listType: fileType, |
| | | fileList: value, |
| | | action: baseUrl, |
| | | fileList: filelist, |
| | | action: null, |
| | | accept: accept, |
| | | method: 'post', |
| | | multiple: true, |
| | | multiple: false, |
| | | onChange: this.onChange, |
| | | onRemove: this.onRemove, |
| | | data: this.getExtraData, |
| | | beforeUpload: this.beforeUpload, |
| | | className: uploadable |
| | | } |
| | | |
| | | return ( |
| | | <Upload {...props}> |
| | | <Button> |
| | | <Icon type="upload" /> 点击上传 |
| | | </Button> |
| | | {fileType !== 'picture-card' ? <Button> |
| | | <UploadOutlined /> 点击上传 |
| | | </Button> : null} |
| | | {fileType === 'picture-card' ? <span style={{whiteSpace: 'nowrap'}}> |
| | | <UploadOutlined /> 点击上传 |
| | | </span> : null} |
| | | {showprogress ? <Progress percent={percent} size="small" /> : null} |
| | | </Upload> |
| | | ) |