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閱讀 227,748評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,165評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,595評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,633評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,435評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,943評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,035評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,175評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,713評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,599評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,788評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,303評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,034評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,412評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,664評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,408評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,747評論 2 370