React使用rc-upload进行文件上传

1. 安装npm i rc-upload(官网https://www.npmjs.com/package/rc-upload)
2. 使用

引入import RcUpload from 'rc-upload'

interface FileUploadProps {
  name?: string // 上传的字段文件名
  action?: string // 上传的路径
  className?: string // 样式类名
  style?: object // 行内样式
  multiple?:boolean // 是否多选
  accept?:string // 允许上传的类型
  size?:number // 限制的大小
  params?: any // 上传的时候的参数
  successChange?: Function // 成功之后
  mobxGlobal?: any
}

interface FileUploadState {
  accept: string
  fileSize: number
  filename: string
  errmsg: string
  errurl: string
  visible: boolean
  progressPercent: number
}

@inject('mobxGlobal')
export default class FileUpload extends RootComponent<FileUploadProps, FileUploadState> {
  basicModel: React.RefObject<BasicModal>

  constructor (props:any) {
    super(props)
    const { accept, size, name } = this.props
    this.state = {
      accept: accept || '.xlsx,.xls', // '.xlsx,.xls'
      fileSize: size || 10,
      filename: name || 'file',
      errmsg: '',
      errurl: '',
      visible: false,
      progressPercent: 0
    }
    this.basicModel = React.createRef()
  }

  /**
   * 组件销毁之前 对 state 的状态做出处理
   */
  componentWillUnmount () {
    this.setState = (state, callback) => {}
  }

  // 开始上传文件:实际不会进行上传的
  onStart = (file:any) => {
    // 文件开始上传
  }

  onProgress = (file:any) => {
    // console.log(file)
  }

  /** 导出之后的下载 */
  showModel = (url:string, msg:string) => {
    this.setState({
      errmsg: msg,
      errurl: url
    })
    this.handleModal(1) // 正常导入的错误的信息
  }

  onSuccess = (res: any, file: any) => {
    let { successChange } = this.props
    if (successChange) {
      successChange(res)
    } else {
      const { errNum, errMessage, excelUrl, successNum } = res.data
      if (errNum > 0) {
        this.showModel(excelUrl, errMessage)
      } else if (errNum < 1 && successNum > 0) {
        this.$message.success('导入成功!')
      } else {
        this.$message.error('导入失败!')
      }
    }
  }

  onError = (err:any, flg:boolean) => {
    const { code, msg } = err
    this.error(msg || err)
    // if (flg) {
    //   if (code === 401) {
    //     this.error(msg)
    //   } else {
    //     this.error('文件格式不正确!')
    //   }
    // } else {
    //   this.error(err)
    // }
  }

  /* 文件上传的 检查 */
  beforeUpload = (file:any, fileList:any) => {
    const { accept, fileSize } = this.state
    const { size, name } = file
    let a = '文件上传出错'
    return new Promise((resolve, reject) => {
      // 对文件的信息进行 类型判断
      let index = name.lastIndexOf('.')
      let typeArry = accept.split(',')
      let suffer = (name as string).substring(index, name.length)
      if (typeArry.indexOf(suffer) < 0) {
        a = '请上传正确的文件'
        this.$message.error(a)
        reject(a)
      }
      if ((size / 1024 / 1024) > fileSize) { // 对文件进行 大小判断
        a = `上传文件的大小不能超过${fileSize}M`
        this.$message.warning(a)
        reject(a)
      }
      resolve(file)
    })
  }

  // /* 自定义的文件上传, 默认的不传,直接成功 */
  // customRequest = (request:any) => {
  //   const { action, file, filename, fileSize, data, onProgress, onSuccess, onError } = request
  //   let formData = new FormData()
  //   let params = this.props.params
  //   // 创建对象的信息
  //   formData.append(filename, file, file.name)
  //   if (params) {
  //     for (const key in params) {
  //       formData.append(key, params[key])
  //     }
  //   }
  //   this.setState({ visible: true, progressPercent: 0 })
  //   let time:any = setInterval(() => {
  //     let { progressPercent } = this.state
  //     if (progressPercent >= 80) {
  //       clearInterval(time)
  //     } else {
  //       progressPercent += 8
  //     }
  //     this.setState({ progressPercent })
  //   }, 1000)
  //   this.axios.upload({
  //     method: 'post',
  //     url: action,
  //     data: formData
  //     // onUploadProgress: (progressEvent:any) => {
  //     //   if (progressEvent.lengthComputable) {
  //     //     this.onUploadProgressLoading(progressEvent)
  //     //   }
  //     // }
  //   }).then((res:any) => {
  //     const { code, data, msg } = res.data
  //     if (code === 200) {
  //       onSuccess(res.data, file)
  //     } else {
  //       onError(res.data, true)
  //     }
  //   }).catch((err:any) => {
  //     onError(err, false)
  //   }).finally(() => {
  //     this.setState({ visible: false, progressPercent: 100 })
  //   })
  // }

  /* 自定义的文件上传, 默认的不传,直接成功 */
  customRequest = (request:any) => {
    const { action, file, filename, fileSize, data, onProgress, onSuccess, onError } = request
    const { mobxGlobal: { setTaskNum } } = this.props
    let formData = new FormData()
    let params = this.props.params
    // 创建对象的信息
    formData.append(filename, file, file.name)
    if (params) {
      for (const key in params) {
        formData.append(key, params[key])
      }
    }
    this.axios.upload({
      method: 'post',
      url: action,
      data: formData
    }).then((res:any) => {
      let { data, code, msg } = res.data
      if (code === 200) {
        this.warning('数据正在导入中,请至任务管理查看报表!')
        this.axios.request(this.api.count).then(({ code, data }) => {
          if (code === 200) {
            let { sun } = data
            sun = sun > 99 ? '99+' : sun
            this.props.mobxGlobal.setTaskNum(sun)
          }
        })
      } else {
        this.warning(`${msg[0]}`)
      }
    }).finally(() => {
      this.setState({ visible: false, progressPercent: 100 })
    })
  }

  /* 打开弹窗: 错误的小消息存在 */
  handleModal = (num: number = 0) => {
    const { handleOk, handleCancel } = this.basicModel.current as BasicModal
    num === 0 ? handleCancel() : handleOk()
  }

  /** 下载数据 */
  dowloadFile = (url:string) => {
    let link = document.createElement('a')
    link.style.display = 'none'
    link.href = url
    document.body.appendChild(link)
    link.click()
    this.handleModal(0)
    this.$message.success('下载成功!')
  }

  /** 上传的进度 */
  // onUploadProgressLoading = ({ total, loaded }:any) => {
  //   let progressPercent:number = (total / loaded) * 100
  //   let visible:boolean = true
  //   this.setState({ visible, progressPercent })
  // }

  render () {
    const { multiple, action, name, style } = this.props
    const { filename, accept, errmsg, errurl, visible, progressPercent } = this.state
    const config = {
      action: action,
      name: filename,
      accept: accept, // 默认上传的是图片
      multiple: multiple, // 多选
      onStart: this.onStart, // 开始上传文件
      onProgress: this.onProgress, // 进度回调,仅适用于现代浏览器
      onSuccess: this.onSuccess, // 成功回调
      onError: this.onError, // 错误回调
      beforeUpload: this.beforeUpload, // 上传前的验证
      customRequest: this.customRequest // 提供默认xhr行为的替代以进行其他自定义
    }
    return (
      <div className="upload-file-content" style={style}>
        <RcUpload {...config}>
          {this.props.children}
        </RcUpload>
        <Modal title="" closable={false} footer={null} visible={visible}>
          <div className="upload-progress">
            <p>正在导入,请稍等...</p>
            <Progress strokeColor={{
              to: '#24C8EA',
              from: '#2B8FF9'
            }}
            status="active" percent={progressPercent} />
          </div>
        </Modal>
        <BasicModal ref={this.basicModel} title="提示">
          <Row>
            <Col span={7} style={{ textAlign: 'center' }}><img src={js}></img></Col>
            <Col span={17} className="error-col">{errmsg}</Col>
          </Row>
          <Row>
            <div className="import-error">
              <p>出错原因可能为:</p>
              <p>1.数据不完整(必填项为空);</p>
              <p>2.字段格式不正确(如导入数据中的“项目”为系统内没有的项目名称等);</p>
              <p>3.与原数据冲突(如导入的员工相关记录在系统中已存在)。</p>
            </div>
          </Row>
          <Row>
            <Button type="primary" onClick={() => (this.dowloadFile(errurl))}>下载出错数据</Button>
          </Row>
        </BasicModal>
      </div>
    )
  }
}

该文件主要用于后台管理系统的导入功能

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280