king
2024-08-06 70f30488f31c2adb1cfb3cb2452ea27c85167019
src/tabviews/zshare/fileupload/index.jsx
@@ -1,142 +1,398 @@
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
  }
  /**
@@ -149,35 +405,37 @@
  }
  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>
    )