-----前端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)