vue 二進制分片上傳

-----前端vue部分

>>1. npm install vue-simple-uploader --save
>>2. main.js中註冊該組件
import uploader from 'vue-simple-uploader'
Vue.use(uploader);

>>3. upload.vue

<template>
  <div class="app-container">
    <div id="global-uploader">
      <!-- 上傳按鈕 -->
      <uploader :autoStart="false" @file-added="onFileAdded">
        <uploader-unsupport></uploader-unsupport>
        <uploader-btn id="global-uploader-btn" >選擇文件</uploader-btn>
      </uploader>
    </div>
    <br>

    <!--文件列表 根據業務需要自行處理-->
    <div>
      <el-table :data="fileList" ref="fileList" highlight-current-row :row-class-name="upFileTableClassName" style="width: 100%;" :header-cell-style="{'text-align':'center'}">
        <el-table-column prop="name" label="文件名" align="center"/>
        <el-table-column prop="command" label="指令" width="300px" align="center">
          <template slot-scope="scope">
            <el-button type="primary" plain size="small" @click="upToServer(scope.$index, scope.row)">上傳</el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
  </div>
</template>


<script>
  import { uploadFilesAPI } from '@/api/mr-control/upload'
  import { generateUUID,timeFormat } from '@/utils/comMethod';
  import Bus from '@/utils/bus';
  import hex_md5 from 'js-md5';

  export default {
    data() {
      return {
        attrs: {
          accept: [], 
        },
        fileList:[],
        opCol:null,
        mapPg:{
          "preparing":"【準備升級】",
          "downloading":"【下載升級包】",
          "upgrading":"【正在升級】",
          "succeeded":"【升級完成】",
        }
      }
    },
    watch:{
    
    },
    methods: {
      //獲取選中文件
      onFileAdded(file) {
        const _this = this;
        const fileinfo = {};
        fileinfo.name = file.name;
        fileinfo.progress = 0; //上傳進度條
        fileinfo.id = generateUUID();
        this.fileList.push(fileinfo);

        //監聽上傳
        Bus.$on('upgradeFileYes_' + fileinfo.id, () => {
          this.upgradeFiles(file,fileinfo).then(succ_data => {
          
          }).catch(fail_data => {
         
          })
        });
      //觸發上傳
      upToServer(index, row) {
        const fdata = Object.assign({}, row);
        Bus.$emit('upgradeFileYes_' + fdata.id, {msg: 'upToServer'})
      },
      //分片上傳
      upgradeFiles(file,fileinfo) {
        return new Promise((resolve, reject) => {
          let fileReader = new FileReader();
          //解決瀏覽器對Blob切片兼容
          let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
          let currentChunk = 0;
          const chunkSize = 1024 * 1024 * 10;
          let chunks = Math.ceil(file.size / chunkSize);
          let promiseList = [];

          file.pause();
          loadNext();

          //讀取成功回調
          fileReader.onload = (e => {
            let content = e.target.result;
            let un8 = new Uint8Array(content);
            const start = currentChunk * chunkSize;
            const end = Math.min(file.size, start + chunkSize);

            const info = {};
            info.name = file.name;
            info.md5 = hex_md5(un8);
            info.offset = start;
            info.length = end - start;

            let fileData = new FormData();
            fileData.append('fileObj', new Blob([un8]));

            promiseList.push(
                new Promise((resv, reje) => {
                  uploadFilesAPI(info, fileData).then(res => {
                    if(res.result){
                      //同步上傳時
                      if(!fileinfo.pfail && currentChunk < chunks - 1) {
   						currentChunk++;
                        loadNext()	
                      }
                      resv()
                    }else{
                      fileinfo.pfail = true;
                      reje()
                    }
                  }).catch(err => {
                    fileinfo.pfail = true;
                    reje()
                  })
                })
            );
            if ((currentChunk < chunks - 1 &&  fileinfo.pfail) || currentChunk >= chunks - 1 ) {
               Promise.all(promiseList).then((res) => {
                 resolve()
               }).catch((err) => { reject() });
            }else{
             	//異步上傳時
            	//currentChunk++;
                //loadNext()
            }
          });
          //讀取失敗回調
          fileReader.onerror = function () {
            reject()
          };
          //切片
          function loadNext() {
            let start = currentChunk * chunkSize;
            let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
            fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
          }
        })
      },
      //請求升級
      upgradeBurn() {   
      },
      //獲取升級進度
      getUpgradeState(file,fileinfo){
      },
      //表格樣式
      upFileTableClassName({row, rowIndex}) {
        return rowIndex % 2 === 1 ? 'warning-row' : 'success-row';
      },
    }
  }
</script>

<style>
  .uploader-btn {
    line-height: 1 !important;
    background: #ecf5ff !important;
    border: 1px solid #b3d8ff !important;
    color: #409EFF !important;
    font-weight: 500 !important;
    padding: 12px 20px !important;
    font-size: 14px !important;
    border-radius:5% !important;

  }
  .uploader-btn:hover{
    background-color: #409EFF !important;
    color: white !important;
  }
  .uploader-btn:active{
    color:yellow !important;
    transform:scale(0.97) !important;
  }
  /** 文件上傳對話框**/
  .dg-upgrader{
    width:40%;
    min-width: 450px;
    min-height: 300px;
    border:1px solid #409EFF;
    box-shadow: 0 0 300px rgba(76, 144, 255, 0.25) inset;
    border-radius: 3px;
  }
</style>

-----後端django 部分

class FilesView(APIView):

    parser_classes = [JSONParser, FormParser, MultiPartParser, FileUploadParser, ]

    def post(self, request, *args, **kwargs):
        offset = request.GET.get('offset')
        length = request.GET.get('length')
        encode = request.GET.get('encode')
        name = request.POST.get('name')
        chunk = math.floor(int(offset) / 1024 * 1024 * 10)
        dir = name.split('.')[0]
        file_data = request.FILES.getlist('fileObj')
        fl = file_data[0]
        filename = '%s_%s' % (offset, length)
        path = default_storage.save('./upload/%s/%s' % (dir,filename), ContentFile(fl.read())
        return Response({'chunk ':chunk ,'result':'true'}, status=status.HTTP_200_OK)
發佈了42 篇原創文章 · 獲贊 20 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章