elementui上传结合oss接口断点续传,现在只差停止上传和继续上传,各大精英帮忙看下
<template>
<div id="templateUpload" class="posi-r" style="padding-bottom: 110px;">
<!-- <div class="posi-a left0 top0 right0 bottom0" style="z-index: 100;" @click="updateIngEvent"
v-show="pageData.updateIng"></div> -->
<div class="title">2-资源上传</div>
<div class="cx-cc pb20 mb20 posi-r" id="contractUploadBox"
style="background-color:rgba(0, 163, 255, 0.03);border: 1px dashed #D9D9DA;">
<img class="w120 mb10" src="@/assets/img/upload_yun.png" alt="">
<p class="color-333 ft16 mb20">点击或文件拖拽到这里上传</p>
<p class="ft16 color-fff ft12 bg-main pt10 pb10 pl40 pr40 c_p mb12 bdr4">点击上传</p>
<p class="ft12 color-999">仅支持MP4视频文件,上传添加不超过500个,单次累计上传文件不超过30M</p>
<input class="posi-a left0 bottom0 top0 right0 opacity0" accept="video/mp4" multiple
type="file" name="" @change="inputUploadChange">
</div>
<div class="rx-bc mb12">
<div class="rx-sc">
<el-dropdown class="mr12">
<span class="el-dropdown-link">
<el-button type="primary">极速上传</el-button>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="1">
<div class="posi-r">
上传文件夹
<input class="posi-a left0 bottom0 top0 right0 opacity0" webkitdirectory multiple
type="file" name="" @change="inputUploadChange">
</div>
</el-dropdown-item>
<el-dropdown-item command="2">
<div class="posi-r">
上传文件
<input class="posi-a left0 bottom0 top0 right0 opacity0"
accept="video/mp4" multiple type="file" name=""
@change="inputUploadChange">
</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-dropdown @command="batchBtnChange">
<span class="el-dropdown-link">
<el-button>批量操作</el-button>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="1">批量删除</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div>
<span class="ft14">已上传/总上传:</span>
<span class="color-03A3FF">{{ fileDatas.list.length }}</span>
<span class="color-999">/500</span>
</div>
</div>
<el-table class="ww100" :data="fileDatas.list">
<el-table-column label="" width="55">
<template #default="scope">
<el-checkbox v-model="scope.row.check"></el-checkbox>
</template>
</el-table-column>
<el-table-column prop="typeName" label="视频文件" width="100">
</el-table-column>
<el-table-column prop="name" label="资源名称">
<template #default="scope">
<div class="color-333 ft14 mb10">{{ scope.row.name }}</div>
</template>
</el-table-column>
<el-table-column label="单集时长">
<template #default="scope">
<div>{{ formatVideoDuration(scope.row.videoDuration) }}</div>
</template>
</el-table-column>
<el-table-column label="上传状态">
<template #default="scope">
<div class="rx-sc" v-if="scope.row.state == 1">
<el-icon color="#25D384">
<CircleCheck />
</el-icon>
<span class="color-25D384 ft14 ml5">已完成</span>
</div>
<div class="rx-sc" v-else>
<div class="flex1 mr12">
<div class="color-666 mb10">{{ scope.row.state == 0 ? '等待中' : scope.row.state == 2 ? '上传失败' :
'上传中' }}
</div>
<div class="posi-r bdr100 bg-C6DFF5" style="height:5px">
<div class="posi-a bdr100 left0 top0 bottom0 bg-0195ED" :style="{ width: scope.row.width }">
</div>
</div>
</div>
<div class="color-03A3FF">{{ scope.row.estimated }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<a href="javascript:;" v-if="scope.row.state == 1" class="t_d_u color-409EFF tool_btn color-red"
@click="remove(scope.$index)">删除</a>
<a href="javascript:;" class="t_d_u color-409EFF tool_btn color-red"
@click="stop(scope.row)">停止上传</a>
<a href="javascript:;" class="t_d_u color-main tool_btn color-red"
@click="continueUpld(scope.row)">继续上传</a>
<a href="javascript:;" v-if="scope.row.state == 2" class="t_d_u color-main tool_btn color-red"
@click="anew(scope.row)">重新上传</a>
<span v-if="scope.row.state == 0">-</span>
</template>
</el-table-column>
</el-table>
<div v-show="pageData.width" class="rx-ec bg-FAFAFA posi-f bottom0" :style="{ width: pageData.width + 'px' }"
style="z-index: 400;">
<div class="color-000 ft16 pt20 pb20 pl40 pr40 c_p" style="background-color: #EAEAEA;" @click="delBack">取消</div>
<div class="color-fff ft16 bg-main pt20 pb20 pl40 pr40 c_p" @click="saveEvent">确定</div>
</div>
<!-- 上传失败 -->
<el-dialog v-model="errorFileData.show" title="文件上传失败提示" width="800px"
:before-close="() => { errorFileData.show = false }">
<div class="p20">
<el-table class="ww100" :data="errorFileData.list">
<el-table-column prop="name" label="文件名称" />
<el-table-column prop="type" label="文件类型" />
<el-table-column label="失败原因">
<template #default="scope">
文件格式有误,请检查后重新上传,支持视频格式:mp4,单集限制30M以内
</template>
</el-table-column>
</el-table>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import axios from 'axios'
import {
ElMessage
} from 'element-plus'
import { useMainPage } from '@/store/modules/app.js';
const mainPage = useMainPage();
const pageData = reactive({
updateIng: false,
width: 0,
options: [],
teacherList: [],
unitId: id || '',
teacherId: '',
teacherName: '',
unitArr: [],
newData:[]
})
// 时分秒
function formatVideoDuration(cellValue) {
if(!cellValue) return ''
let minutes = Math.floor(cellValue / 60);
let seconds = cellValue % 60;
return `${minutes}分${seconds.toFixed(0)}秒`;
}
const fileDatas = reactive({
list: []
})
function inputUploadChange(e) {
var arr = Array.from(e.target.files);
var videos = [], orders = [];
arr.forEach(n => {
if (n.type.indexOf('mp4') > -1 && n.size / 1024 / 1024 < 30) {
let isItem = fileDatas.list.find(item=>item.nameStatus==n.name) // 如果上传的剧集中已经存在提示已经存在
if(isItem){
return ElMessage.warning(`${n.name}该视频已经上传!`);
}
videos.push(n);
} else {
orders.push(n);
}
})
if (orders.length > 0) {
errorFile(orders);
}
if(videos.length > 0) {
uploadStart(videos);
}
}
function remove(index) {
fileDatas.list.splice(index, 1);
}
var uploadArr = [], oldArr = [];
function uploadStart(files) {
if (files.length == 0) {
ElMessage.warning("未检测到文件");
return false;
}
pageData.updateIng = true;
var beforeNum = fileDatas.list.length;//记录这次上传之前 已经上传了多少个
files.forEach(n => {
n.numIndex = beforeNum;
fileDatas.list.push({
numIndex: beforeNum,//记录索引
url: '',
nameStatus:n.name,
name: n.name.split('.')[0],
typeName:n.name.split('.')[1],
newSize: (n.size / 1024 / 1024).toFixed(2) + 'MB',
size: n.size,
check: false,
teacherId: pageData.teacherId,
width: '0%',
estimated: '0MB/s',
state: 0,
videoDuration: 0
})
beforeNum++;
})
uploadArr = files.splice(0, 1);
oldArr = files;
startUpload(uploadArr);
}
var timer = '', overNum = 0;//上传完几个
function overUpload() {
overNum++;
clearTimeout(timer);
timer = setTimeout(() => {
uploadArr.splice(0, overNum); //去掉上传队列中上传完的
if (oldArr.length) {
var arr = oldArr.splice(0, overNum); //拿几个补到到上传队列
overNum = 0;//初始上传完成数
uploadArr = [...arr, ...uploadArr];
startUpload(arr);//开始上传
}
}, 500)
}
function startUpload(arr) {
for (var i = 0; i < arr.length; i++) {
uploadFun(arr[i]);
}
}
let uploadProgress = {}; // 存储每个文件的上传进度
let cancelTokens = {}; // 存储每个文件的取消令牌
// 停止上传
function stop(val){
}
// 继续上传
function continueUpld(val){
}
function uploadFun(item) {
let data = pageData.newData.find(val=>val.name==item.name) //记录上传视频item
if(!data){
pageData.newData.push(item)
}
let nowIndex = item.numIndex;//i+beforeNum; //取到当前正在上传的索引
getVideoTime(item, (videoDuration) => {
fileDatas.list[nowIndex].videoDuration = videoDuration;
})
fileDatas.list[nowIndex].state = 3;
commonUpload({ fileData: item }, (formData, ossUrl, fileData) => {
let param = new FormData();
for (var k in formData) {
param.append(k, formData[k]);
}
param.append("file", fileData.fileData);
let uploadTime = (new Date()).getTime();
let oldByte = 0;
axios.request({
url: ossUrl,
method: 'post',
headers: { "Content-Type": "multipart/form-data" },
data: param,
onUploadProgress: function (progressEvent) {
var { progress, estimated, loaded } = progressEvent;
fileDatas.list[nowIndex].width = progress * 100 + '%';
let nowTime = (new Date()).getTime();
if (nowTime - uploadTime > 1000) {
let nowByte = (loaded - oldByte) / 1024 / 1024;
fileDatas.list[nowIndex].estimated = nowByte.toFixed(2) + 'MB/s';
uploadTime = nowTime;
oldByte = loaded;
}
},
}).then((res) => {
if (res.code == 0) {
fileDatas.list[nowIndex].state = 1;
fileDatas.list[nowIndex].url = res.results.wholeUrl;
} else {
fileDatas.list[nowIndex].state = 2;
}
var success = fileDatas.list.filter(n => n.state > 0);
if (success.length == fileDatas.list.length) { //上传完了
pageData.updateIng = false;
} else {
overUpload();
}
})
})
}
function getVideoTime(file, callback) {
var reader = new FileReader();
reader.onload = function (e) {
var video = document.createElement('video');
video.preload = 'metadata';
// 当视频的元数据已加载后,获取视频时长
video.onloadedmetadata = function () {
window.URL.revokeObjectURL(video.src);
callback && callback(video.duration);
};
video.src = URL.createObjectURL(file);
};
reader.readAsArrayBuffer(file);
}
//上传失败提示
const errorFileData = reactive({
show: false,
list: []
})
function errorFile(list) {
if (list.length > 0) {
errorFileData.list = list;
errorFileData.show = true;
}
}
</script>
commonUpload是调用的是oss上传接口