|
@@ -293,7 +293,7 @@
|
|
|
:percentage="currentUploadProgress.line1"
|
|
|
:show-text="false"
|
|
|
:width="30"
|
|
|
- :status="currentUploadProgress.line1Status === 'success' ? 'success' :
|
|
|
+ :status="currentUploadProgress.line1Status === 'success' ? 'success' :
|
|
|
currentUploadProgress.line1Status === 'failed' ? 'exception' : ''"
|
|
|
></el-progress>
|
|
|
<span class="line-status-text">{{ Math.round(currentUploadProgress.line1) }}%</span>
|
|
@@ -304,7 +304,7 @@
|
|
|
:percentage="currentUploadProgress.line2"
|
|
|
:show-text="false"
|
|
|
:width="30"
|
|
|
- :status="currentUploadProgress.line2Status === 'success' ? 'success' :
|
|
|
+ :status="currentUploadProgress.line2Status === 'success' ? 'success' :
|
|
|
currentUploadProgress.line2Status === 'failed' ? 'exception' : ''"
|
|
|
></el-progress>
|
|
|
<span class="line-status-text">{{ Math.round(currentUploadProgress.line2) }}%</span>
|
|
@@ -412,8 +412,8 @@
|
|
|
<div class="batch-upload-progress">
|
|
|
<div class="total-progress-row">
|
|
|
<span class="progress-label">总进度:</span>
|
|
|
- <el-progress
|
|
|
- :percentage="scope.row.progress || 0"
|
|
|
+ <el-progress
|
|
|
+ :percentage="scope.row.progress || 0"
|
|
|
:status="getProgressStatus(scope.row)"
|
|
|
:show-text="true"
|
|
|
:format="() => `${Math.round(scope.row.progress || 0)}%`"
|
|
@@ -422,9 +422,9 @@
|
|
|
<div v-if="scope.row.uploadDetails" class="line-progress-rows">
|
|
|
<div class="line-progress-row">
|
|
|
<span class="line-label">线路1:</span>
|
|
|
- <el-progress
|
|
|
+ <el-progress
|
|
|
:percentage="scope.row.uploadDetails.line1 || 0"
|
|
|
- :status="scope.row.uploadDetails.line1Status === 'success' ? 'success' :
|
|
|
+ :status="scope.row.uploadDetails.line1Status === 'success' ? 'success' :
|
|
|
scope.row.uploadDetails.line1Status === 'failed' ? 'exception' : 'warning'"
|
|
|
:show-text="false"
|
|
|
style="width: 60px;"
|
|
@@ -433,9 +433,9 @@
|
|
|
</div>
|
|
|
<div class="line-progress-row">
|
|
|
<span class="line-label">线路2:</span>
|
|
|
- <el-progress
|
|
|
+ <el-progress
|
|
|
:percentage="scope.row.uploadDetails.line2 || 0"
|
|
|
- :status="scope.row.uploadDetails.line2Status === 'success' ? 'success' :
|
|
|
+ :status="scope.row.uploadDetails.line2Status === 'success' ? 'success' :
|
|
|
scope.row.uploadDetails.line2Status === 'failed' ? 'exception' : 'warning'"
|
|
|
:show-text="false"
|
|
|
style="width: 60px;"
|
|
@@ -445,7 +445,7 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
-
|
|
|
+
|
|
|
</el-table-column>
|
|
|
<el-table-column label="操作" align="center" width="150">
|
|
|
<template slot-scope="scope">
|
|
@@ -465,7 +465,7 @@
|
|
|
type="text"
|
|
|
icon="el-icon-refresh"
|
|
|
@click="retryBatchUpload(scope.row)"
|
|
|
- style="color: #E6A23C;">重试</el-button>
|
|
|
+ style="color: #E6A23C;">重试</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
@@ -1141,13 +1141,21 @@ export default {
|
|
|
async getFirstThumbnail(file, form){
|
|
|
try {
|
|
|
//截取小文件
|
|
|
+ // 打印原始文件名和大小
|
|
|
+ console.log("原始文件名:", file.name);
|
|
|
+ console.log("原始文件大小:", file.size, "bytes");
|
|
|
+ console.log("原始文件类型:", file.type);
|
|
|
+
|
|
|
+ // 截取小文件
|
|
|
const clippedBlob = await this.clipVideoFirstTwoSeconds(file);
|
|
|
+ console.log("clippedBlob:::::::::", clippedBlob);
|
|
|
+ console.log("截取后的Blob大小:", clippedBlob.size, "bytes");
|
|
|
+ console.log("截取后的Blob类型:", clippedBlob.type);
|
|
|
|
|
|
const clippedFile = new File([clippedBlob], 'clipped_video.mp4', {
|
|
|
type: 'video/mp4',
|
|
|
lastModified: Date.now()
|
|
|
});
|
|
|
- console.log("调用请请求---------------》",response)
|
|
|
// 3. 调用接口获取封面
|
|
|
const response = await getThumbnail(clippedFile);
|
|
|
console.log("获取封面请求---------------》",response)
|
|
@@ -1156,63 +1164,38 @@ export default {
|
|
|
console.error('获取封面失败:', error);
|
|
|
}
|
|
|
},
|
|
|
+
|
|
|
//截取大文件视频
|
|
|
- clipVideoFirstTwoSeconds(file) {
|
|
|
+ async clipVideoFirstTwoSeconds(file) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- // 创建视频元素用于处理
|
|
|
const video = document.createElement('video');
|
|
|
video.src = URL.createObjectURL(file);
|
|
|
- video.crossOrigin = 'anonymous';
|
|
|
- video.preload = 'metadata';
|
|
|
-
|
|
|
- // 视频元数据加载完成后开始处理
|
|
|
- video.onloadedmetadata = async () => {
|
|
|
- try {
|
|
|
- // 计算截取时长
|
|
|
- const duration = Math.min(2, video.duration);
|
|
|
-
|
|
|
- // 直接从视频元素捕获流
|
|
|
- const stream = video.captureStream();
|
|
|
-
|
|
|
- // 创建 MediaRecorder 录制截取的片段
|
|
|
- const mediaRecorder = new MediaRecorder(stream);
|
|
|
- const chunks = [];
|
|
|
-
|
|
|
- // 收集录制的视频数据
|
|
|
- mediaRecorder.ondataavailable = (e) => chunks.push(e.data);
|
|
|
-
|
|
|
- // 录制结束后处理结果
|
|
|
- mediaRecorder.onstop = () => {
|
|
|
- // 合并数据为 Blob(MP4 格式)
|
|
|
- const blob = new Blob(chunks, { type: 'video/mp4' });
|
|
|
- resolve(blob);
|
|
|
-
|
|
|
- // 清理资源
|
|
|
- URL.revokeObjectURL(video.src);
|
|
|
- stream.getTracks().forEach(track => track.stop());
|
|
|
- };
|
|
|
-
|
|
|
- // 开始录制
|
|
|
- mediaRecorder.start();
|
|
|
-
|
|
|
- // 播放视频并在指定时间后停止录制
|
|
|
- video.currentTime = 0; // 从开头开始
|
|
|
- video.play();
|
|
|
-
|
|
|
- // 到达截取时长后停止录制
|
|
|
- setTimeout(() => {
|
|
|
- video.pause();
|
|
|
- mediaRecorder.stop();
|
|
|
- }, duration * 1000); // 转换为毫秒
|
|
|
-
|
|
|
- } catch (error) {
|
|
|
- reject(new Error('视频截取失败: ' + error.message));
|
|
|
- }
|
|
|
+ video.muted = true;
|
|
|
+ video.playsInline = true;
|
|
|
+
|
|
|
+ video.onloadedmetadata = () => {
|
|
|
+ video.currentTime = 0; // 定位到第一帧
|
|
|
+ video.onseeked = () => {
|
|
|
+ const canvas = document.createElement('canvas');
|
|
|
+ canvas.width = video.videoWidth;
|
|
|
+ canvas.height = video.videoHeight;
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
|
+
|
|
|
+ canvas.toBlob(
|
|
|
+ (blob) => {
|
|
|
+ URL.revokeObjectURL(video.src);
|
|
|
+ resolve(blob); // 返回 JPEG Blob
|
|
|
+ },
|
|
|
+ 'image/jpeg',
|
|
|
+ 0.8 // 质量
|
|
|
+ );
|
|
|
+ };
|
|
|
};
|
|
|
|
|
|
- // 视频加载错误处理
|
|
|
video.onerror = () => {
|
|
|
- reject(new Error('视频加载失败,请检查文件格式'));
|
|
|
+ URL.revokeObjectURL(video.src);
|
|
|
+ reject(new Error('视频加载失败'));
|
|
|
};
|
|
|
});
|
|
|
},
|
|
@@ -1221,11 +1204,11 @@ export default {
|
|
|
try {
|
|
|
// 更新线路1状态为上传中
|
|
|
this.updateUploadProgress('line1Status', 'uploading');
|
|
|
-
|
|
|
+
|
|
|
const data = await uploadObject(file, (progress) => {
|
|
|
const progressPercent = Math.floor(progress.percent * 100);
|
|
|
this.updateUploadProgress('line1', progressPercent);
|
|
|
-
|
|
|
+
|
|
|
const progressEvent = {
|
|
|
percent: progressPercent,
|
|
|
loaded: progress.loaded,
|
|
@@ -1234,16 +1217,16 @@ export default {
|
|
|
};
|
|
|
onProgress(progressEvent);
|
|
|
}, 1);
|
|
|
-
|
|
|
+
|
|
|
let line_1 = `${process.env.VUE_APP_VIDEO_LINE_1}${data.urlPath}`;
|
|
|
form.fileKey = data.urlPath.substring(1);
|
|
|
form.videoUrl = line_1;
|
|
|
form.line1 = line_1;
|
|
|
-
|
|
|
+
|
|
|
// 更新线路1状态为成功
|
|
|
this.updateUploadProgress('line1Status', 'success');
|
|
|
this.updateUploadProgress('line1', 100);
|
|
|
-
|
|
|
+
|
|
|
this.$message.success("线路一上传成功");
|
|
|
return { success: true, url: line_1 };
|
|
|
} catch (error) {
|
|
@@ -1258,11 +1241,11 @@ export default {
|
|
|
try {
|
|
|
// 更新线路2状态为上传中
|
|
|
this.updateUploadProgress('line2Status', 'uploading');
|
|
|
-
|
|
|
+
|
|
|
const data = await uploadToOBS(file, (progress) => {
|
|
|
const progressPercent = Math.floor(progress);
|
|
|
this.updateUploadProgress('line2', progressPercent);
|
|
|
-
|
|
|
+
|
|
|
const progressEvent = {
|
|
|
percent: progressPercent,
|
|
|
loaded: progress,
|
|
@@ -1271,13 +1254,13 @@ export default {
|
|
|
};
|
|
|
onProgress(progressEvent);
|
|
|
}, 1);
|
|
|
-
|
|
|
+
|
|
|
form.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
|
|
|
-
|
|
|
+
|
|
|
// 更新线路2状态为成功
|
|
|
this.updateUploadProgress('line2Status', 'success');
|
|
|
this.updateUploadProgress('line2', 100);
|
|
|
-
|
|
|
+
|
|
|
this.$message.success("线路二上传成功");
|
|
|
return { success: true, url: form.line2 };
|
|
|
} catch (error) {
|
|
@@ -1290,12 +1273,12 @@ export default {
|
|
|
// 更新上传进度的辅助方法
|
|
|
updateUploadProgress(key, value) {
|
|
|
this.currentUploadProgress[key] = value;
|
|
|
-
|
|
|
+
|
|
|
// 计算总进度:只有两个线路都成功才算100%
|
|
|
- if (this.currentUploadProgress.line1Status === 'success' &&
|
|
|
+ if (this.currentUploadProgress.line1Status === 'success' &&
|
|
|
this.currentUploadProgress.line2Status === 'success') {
|
|
|
this.currentUploadProgress.total = 100;
|
|
|
- } else if (this.currentUploadProgress.line1Status === 'failed' ||
|
|
|
+ } else if (this.currentUploadProgress.line1Status === 'failed' ||
|
|
|
this.currentUploadProgress.line2Status === 'failed') {
|
|
|
// 如果任一线路失败,总进度保持当前状态
|
|
|
this.currentUploadProgress.total = Math.min(
|
|
@@ -1314,10 +1297,10 @@ export default {
|
|
|
async videoUpload(options) {
|
|
|
this.isUploading = true;
|
|
|
this.form.uploadStatus = 'uploading';
|
|
|
-
|
|
|
+
|
|
|
const file = options.file;
|
|
|
this.getMediaDuration(file);
|
|
|
-
|
|
|
+
|
|
|
// 重置进度
|
|
|
this.currentUploadProgress = {
|
|
|
total: 0,
|
|
@@ -1363,17 +1346,17 @@ export default {
|
|
|
line1Status: this.currentUploadProgress.line1Status,
|
|
|
line2Status: this.currentUploadProgress.line2Status
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
const failedLines = [];
|
|
|
if (!line1Success) failedLines.push('线路1');
|
|
|
if (!line2Success) failedLines.push('线路2');
|
|
|
-
|
|
|
+
|
|
|
this.$message.error(`视频上传失败!${failedLines.join('、')} 上传失败,请重试`);
|
|
|
}
|
|
|
|
|
|
this.form.fileName = file.name;
|
|
|
this.form.fileSize = file.size;
|
|
|
-
|
|
|
+
|
|
|
} catch (error) {
|
|
|
this.form.uploadStatus = 'failed';
|
|
|
this.$message.error("视频上传过程中发生错误,请重试");
|
|
@@ -1612,11 +1595,11 @@ export default {
|
|
|
// 失败时保持当前进度,不设为100%
|
|
|
this.updateBatchProgress(index);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
const failedLines = [];
|
|
|
if (!line1Success) failedLines.push('线路1');
|
|
|
if (!line2Success) failedLines.push('线路2');
|
|
|
-
|
|
|
+
|
|
|
this.$message.error(`文件 ${file.name} 在 ${failedLines.join('、')} 上传失败`);
|
|
|
}
|
|
|
|
|
@@ -1914,12 +1897,12 @@ export default {
|
|
|
const item = this.videoList[index];
|
|
|
const line1Progress = item.uploadDetails.line1 || 0;
|
|
|
const line2Progress = item.uploadDetails.line2 || 0;
|
|
|
-
|
|
|
+
|
|
|
// 只有两个线路都成功才算100%
|
|
|
- if (item.uploadDetails.line1Status === 'success' &&
|
|
|
+ if (item.uploadDetails.line1Status === 'success' &&
|
|
|
item.uploadDetails.line2Status === 'success') {
|
|
|
item.progress = 100;
|
|
|
- } else if (item.uploadDetails.line1Status === 'failed' ||
|
|
|
+ } else if (item.uploadDetails.line1Status === 'failed' ||
|
|
|
item.uploadDetails.line2Status === 'failed') {
|
|
|
// 如果任一线路失败,总进度保持当前状态,不超过99%
|
|
|
item.progress = Math.min((line1Progress + line2Progress) / 2, 99);
|
|
@@ -1936,7 +1919,7 @@ export default {
|
|
|
|
|
|
// const {line1, line2,line1Status,line2Status} = this.videoList[index].uploadDetails
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
// // 重置状态
|
|
|
// this.videoList[index].uploadStatus = 'uploading';
|
|
@@ -1949,7 +1932,7 @@ export default {
|
|
|
// };
|
|
|
|
|
|
// const tempVideo = this.videoList[index];
|
|
|
-
|
|
|
+
|
|
|
// try {
|
|
|
// // 重新上传
|
|
|
// // const [line1Result, line2Result] = await Promise.allSettled([
|
|
@@ -2008,11 +1991,11 @@ export default {
|
|
|
|
|
|
const tempVideo = this.videoList[index];
|
|
|
const uploadDetails = tempVideo.uploadDetails || {};
|
|
|
-
|
|
|
+
|
|
|
// 检查哪些线路需要重试
|
|
|
const needRetryLine1 = uploadDetails.line1Status === 'failed' || uploadDetails.line1Status === 'pending';
|
|
|
const needRetryLine2 = uploadDetails.line2Status === 'failed' || uploadDetails.line2Status === 'pending';
|
|
|
-
|
|
|
+
|
|
|
if (!needRetryLine1 && !needRetryLine2) {
|
|
|
this.$message.info('所有线路都已上传成功,无需重试');
|
|
|
return;
|
|
@@ -2020,7 +2003,7 @@ export default {
|
|
|
|
|
|
// 更新整体状态为上传中
|
|
|
this.videoList[index].uploadStatus = 'uploading';
|
|
|
-
|
|
|
+
|
|
|
// 只重置需要重试的线路状态
|
|
|
if (needRetryLine1) {
|
|
|
this.videoList[index].uploadDetails.line1 = 0;
|
|
@@ -2033,7 +2016,7 @@ export default {
|
|
|
|
|
|
try {
|
|
|
const uploadPromises = [];
|
|
|
-
|
|
|
+
|
|
|
// 根据需要重试的线路创建上传任务
|
|
|
if (needRetryLine1) {
|
|
|
uploadPromises.push(
|
|
@@ -2045,7 +2028,7 @@ export default {
|
|
|
// 如果线路1不需要重试,创建一个已成功的Promise
|
|
|
uploadPromises.push(Promise.resolve({ line: 'line1', result: { success: true } }));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (needRetryLine2) {
|
|
|
uploadPromises.push(
|
|
|
this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo)
|
|
@@ -2059,12 +2042,12 @@ export default {
|
|
|
|
|
|
// 等待所有上传任务完成
|
|
|
const results = await Promise.all(uploadPromises);
|
|
|
-
|
|
|
+
|
|
|
// 处理结果
|
|
|
let line1Success = true;
|
|
|
let line2Success = true;
|
|
|
let retryMessages = [];
|
|
|
-
|
|
|
+
|
|
|
results.forEach(({ line, result }) => {
|
|
|
if (line === 'line1') {
|
|
|
line1Success = result.success;
|
|
@@ -2104,7 +2087,7 @@ export default {
|
|
|
this.updateBatchProgress(index);
|
|
|
this.$message.error(`文件 ${tempVideo.fileName} 重试完成:${retryMessages.join(',')}`);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
} catch (error) {
|
|
|
this.videoList[index].uploadStatus = 'failed';
|
|
|
this.$message.error(`文件 ${tempVideo.fileName} 重试过程中发生错误:${error.message || '未知错误'}`);
|
|
@@ -2201,7 +2184,7 @@ export default {
|
|
|
}
|
|
|
return '';
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
</script>
|