| | |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import moment from 'moment' |
| | | import { Upload, Button, Icon, Progress, notification } from 'antd' |
| | | import { Upload, Button, Progress, notification } from 'antd' |
| | | import { UploadOutlined } from '@ant-design/icons' |
| | | import SparkMD5 from 'spark-md5' |
| | | import Api from '@/api' |
| | | import './index.scss' |
| | | |
| | | let service = '' |
| | | if (process.env.NODE_ENV === 'production') { |
| | | service = document.location.origin + '/' + window.GLOB.service |
| | | } else { |
| | | service = window.GLOB.location + '/' + window.GLOB.service |
| | | } |
| | | import Api from '@/api' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import './index.scss' |
| | | |
| | | class FileUpload extends Component { |
| | | static propTpyes = { |
| | | config: PropTypes.object, // 表单信息 |
| | | onChange: PropTypes.func, // 表单变化 |
| | | data: PropTypes.any, |
| | | config: PropTypes.object, |
| | | onChange: PropTypes.func, |
| | | } |
| | | |
| | | state = { |
| | |
| | | maxFile: null, |
| | | rduri: '', |
| | | limit: 2, |
| | | compress: false, |
| | | compress: 'false', |
| | | fileType: 'text', |
| | | showprogress: false, |
| | | maxSize: 0, |
| | | filelist: [] |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { config } = this.props |
| | | const { config, data } = this.props |
| | | |
| | | let filelist = [] |
| | | if (config.initval) { |
| | | try { |
| | | filelist = config.initval.split(',').map((url, index) => { |
| | | return { |
| | | uid: `${index}`, |
| | | name: url.slice(url.lastIndexOf('/') + 1), |
| | | status: 'done', |
| | | url: url, |
| | | origin: true |
| | | 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] |
| | | } |
| | | }) |
| | | } catch (e) { |
| | | filelist = [] |
| | | } |
| | | } |
| | | } |
| | | |
| | | let accept = '' |
| | | let accepts = null |
| | | let compress = false |
| | | if (config.compress === 'true') { |
| | | compress = true |
| | | 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(',') |
| | | accept = config.suffix |
| | | accepts = config.suffix.split(',').map(item => { |
| | | if (!/^\./ig.test(item)) { |
| | | item = '.' + item |
| | | } |
| | | return item |
| | | }) |
| | | accept = accepts.join(',') |
| | | } |
| | | let rduri = config.rduri || '' |
| | | |
| | |
| | | filelist, |
| | | compress, |
| | | limit: config.limit || 2, |
| | | maxFile: config.maxfile && config.maxfile > 0 ? config.maxfile : null, |
| | | maxSize: config.maxSize || 0, |
| | | maxFile: maxFile, |
| | | fileType: config.fileType || 'text' |
| | | }) |
| | | } |
| | |
| | | this.props.onChange(vals.join(',')) |
| | | } |
| | | |
| | | onUpdate = (url) => { |
| | | onUpdate = (url, file_name) => { |
| | | const { config } = this.props |
| | | |
| | | let filelist = fromJS(this.state.filelist).toJS() |
| | | |
| | | if (filelist[filelist.length -1]) { |
| | |
| | | }) |
| | | |
| | | this.setState({filelist}) |
| | | this.props.onChange(vals.join(',')) |
| | | |
| | | 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) => { |
| | |
| | | }) |
| | | } |
| | | |
| | | shardupload = (params) => { |
| | | let param = params.chunks.shift() |
| | | shardupload = (param, file_name) => { |
| | | let form = new FormData() |
| | | |
| | | form.append('file', param.binary) |
| | | form.append('fileMd5', params.file.fileMd5) |
| | | form.append('shardingMd5', param.chunkMd5) |
| | | form.append('baseDomain', service) |
| | | form.append('fileMd5', param.fileMd5) |
| | | form.append('shardingMd5', param.fileMd5) |
| | | form.append('baseDomain', window.GLOB.baseurl) |
| | | form.append('rootPath', 'Content/images/upload/') |
| | | form.append('fileName', params.file.fileName) |
| | | form.append('fileExt', params.file.fileType) |
| | | form.append('shardingCnt', param.chunks) |
| | | form.append('shardingNo', param.chunk) |
| | | form.append('fileName', param.fileName) |
| | | form.append('fileExt', param.fileType) |
| | | form.append('shardingCnt', 1) |
| | | form.append('shardingNo', 1) |
| | | form.append('LoginUID', sessionStorage.getItem('LoginUID') || '') |
| | | form.append('UserID', sessionStorage.getItem('UserID') || '') |
| | | |
| | | Api.getLargeFileUpload(form).then(res => { |
| | | if (res.status) { |
| | | if (params.chunks.length > 0) { |
| | | this.setState({ |
| | | percent: Math.floor(100 * (param.chunk / param.chunks)) |
| | | }) |
| | | this.shardupload(params) |
| | | if (res.urlPath) { |
| | | this.onUpdate(res.urlPath, file_name) |
| | | } else { |
| | | if (res.urlPath) { |
| | | this.onUpdate(res.urlPath) |
| | | } else { |
| | | this.onFail() |
| | | } |
| | | this.setState({ |
| | | percent: 100 |
| | | }, () => { |
| | | setTimeout(() => { |
| | | this.setState({ |
| | | showprogress: false, |
| | | percent: 0 |
| | | }) |
| | | }, 200) |
| | | }) |
| | | this.onFail() |
| | | } |
| | | this.setState({ |
| | | percent: 100 |
| | | }, () => { |
| | | setTimeout(() => { |
| | | this.setState({ |
| | | showprogress: false, |
| | | percent: 0 |
| | | }) |
| | | }, 200) |
| | | }) |
| | | } else { |
| | | this.onFail(res.message) |
| | | } |
| | |
| | | } |
| | | |
| | | beforeUpload = (file) => { |
| | | const { accepts, compress, limit, rduri } = this.state |
| | | const { accepts, compress, limit, rduri, maxSize } = this.state |
| | | |
| | | if (accepts && file.name) { |
| | | let pass = false |
| | |
| | | }) |
| | | |
| | | if (!pass) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '文件格式错误!', |
| | | duration: 5 |
| | | }) |
| | | return |
| | | 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 |
| | | } |
| | | } |
| | | |
| | |
| | | percent: 0 |
| | | }) |
| | | |
| | | if (compress) { |
| | | let file_name = file.name |
| | | |
| | | if (compress === 'true' || compress === 'base64') { |
| | | let reader = new FileReader() |
| | | let fileSize = file.size / 1024 / 1024 |
| | | let compressRate = 0.9 |
| | |
| | | |
| | | let param = {Base64Img: cvs.toDataURL('image/jpeg', compressRate)} |
| | | |
| | | if (rduri) { |
| | | param.rduri = rduri |
| | | } |
| | | |
| | | Api.fileuploadbase64(param).then(result => { |
| | | if (result.status && result.Images) { |
| | | let url = service + result.Images |
| | | |
| | | if (rduri) { |
| | | url = rduri.replace(/webapi(.*)$/, '') + result.Images |
| | | } |
| | | |
| | | this.onUpdate(url) |
| | | |
| | | this.setState({ |
| | | percent: 100 |
| | | }, () => { |
| | | setTimeout(() => { |
| | | this.setState({ |
| | | showprogress: false, |
| | | percent: 0 |
| | | }) |
| | | }, 200) |
| | | }) |
| | | } else { |
| | | this.onFail(result.message) |
| | | 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 = () => { |
| | |
| | | |
| | | 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 blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice |
| | | let chunkSize = 1024 * 1024 * 2 // 切片每次2M |
| | | let chunks = Math.ceil(file.size / chunkSize) // 切片总数 |
| | | let currentChunk = 0 // 当前上传的chunk |
| | | let spark = new SparkMD5.ArrayBuffer() // 对arrayBuffer数据进行md5加密,产生一个md5字符串 |
| | | let chunkFileReader = new FileReader() // 用于计算出每个chunkMd5 |
| | | let totalFileReader = new FileReader() // 用于计算出总文件的fileMd5 |
| | | let params = {chunks: [], file: {}} // 用于上传所有分片的md5信息 |
| | | let param = {} |
| | | |
| | | params.file.fileName = file.name.replace(/\.{1}[^.]*$/ig, '') // 文件名(去除后缀名) |
| | | params.file.fileType = file.name.replace(/^.*\.{1}/ig, '') // 文件类型 |
| | | params.file.fileSize = file.size // 文件大小 |
| | | params.file.fileChunks = chunks // 记录所有chunks的长度 |
| | | param.fileName = file.name.replace(/\.{1}[^.]*$/ig, '') // 文件名(去除后缀名) |
| | | param.fileType = file.name.replace(/^.*\.{1}/ig, '') // 文件类型 |
| | | |
| | | if (!/^[A-Za-z0-9]+$/.test(params.file.fileName)) { // 文件名称含有英文及数字之外字符时,名称系统生成 |
| | | params.file.fileName = moment().format('YYYYMMDDHHmmss') + this.getuuid() |
| | | if (!/^[A-Za-z0-9]+$/.test(param.fileName)) { // 文件名称含有英文及数字之外字符时,名称系统生成 |
| | | param.fileName = moment().format('YYYYMMDDHHmmss') + this.getuuid() |
| | | } |
| | | |
| | | totalFileReader.readAsArrayBuffer(file) |
| | | totalFileReader.onload = (e) => { // 对整个totalFile生成md5 |
| | | spark.append(e.target.result) |
| | | params.file.fileMd5 = spark.end() // 计算整个文件的fileMd5 |
| | | param.fileMd5 = spark.end() // 计算整个文件的fileMd5 |
| | | param.binary = file |
| | | |
| | | let _param = new FormData() |
| | | _param.append('fileMd5', params.file.fileMd5) |
| | | _param.append('fileMd5', param.fileMd5) |
| | | |
| | | Api.getFilePreUpload(_param).then(res => { |
| | | if (res.status && res.urlPath) { |
| | | this.onUpdate(res.urlPath) |
| | | this.onUpdate(res.urlPath, file_name) |
| | | this.setState({ |
| | | percent: 100 |
| | | }, () => { |
| | |
| | | }) |
| | | }, 200) |
| | | }) |
| | | } else if (res.shardings && res.shardings.length > 0) { |
| | | res.shardings.forEach(shard => { |
| | | if (shard.shardingNo && parseInt(shard.shardingNo) > currentChunk) { |
| | | currentChunk = parseInt(shard.shardingNo) |
| | | } |
| | | }) |
| | | loadNext() |
| | | } else { |
| | | loadNext() |
| | | this.shardupload(param, file_name) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | chunkFileReader.onload = (e) => { |
| | | spark.append(e.target.result) // 对每一片分片进行md5加密 |
| | | |
| | | params.chunks[params.chunks.length - 1].chunkMd5 = spark.end() // 添加切片md5 |
| | | |
| | | currentChunk++ // 每一次分片onload,currentChunk都需要增加,以便来计算分片的次数 |
| | | |
| | | if (currentChunk < chunks) { // 当前切片总数没有达到总数时 |
| | | loadNext() |
| | | } else { |
| | | this.shardupload(params) |
| | | } |
| | | } |
| | | |
| | | chunkFileReader.onerror = () => { |
| | | this.onFail('文件读取失败!') |
| | | } |
| | | totalFileReader.onerror = () => { |
| | | this.onFail('文件读取失败!') |
| | | } |
| | | |
| | | let loadNext = () => { |
| | | let start = currentChunk * chunkSize // 计算分片的起始位置 |
| | | let end = Math.min(file.size, start + chunkSize) // 计算分片的结束位置 |
| | | |
| | | let obj = { // 每一个分片需要包含的信息 |
| | | chunk: currentChunk + 1, |
| | | binary: file.slice(start, end), |
| | | start: start, |
| | | end: end, |
| | | chunks |
| | | } |
| | | |
| | | params.chunks.push(obj) |
| | | chunkFileReader.readAsArrayBuffer(blobSlice.call(file, start, end)) |
| | | } |
| | | |
| | | return false |
| | |
| | | return ( |
| | | <Upload {...props}> |
| | | {fileType !== 'picture-card' ? <Button> |
| | | <Icon type="upload" /> 点击上传 |
| | | <UploadOutlined /> 点击上传 |
| | | </Button> : null} |
| | | {fileType === 'picture-card' ? <span style={{whiteSpace: 'nowrap'}}> |
| | | <Icon type="upload" /> 点击上传 |
| | | <UploadOutlined /> 点击上传 |
| | | </span> : null} |
| | | {showprogress ? <Progress percent={percent} size="small" /> : null} |
| | | </Upload> |