三七 před 3 týdny
rodič
revize
a7aa058f55

+ 5 - 0
.env.prod-syysy

@@ -27,6 +27,11 @@ VUE_APP_VIDEO_LINE_1 = https://syysytcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://syysyobs.ylrztop.com
 
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://syysyvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = syysy-2114522511
+
 # 开发环境配置
 ENV = 'development'
 

+ 34 - 0
src/api/course/userVideo.js

@@ -104,3 +104,37 @@ export function getThumbnail(file) {
     }
   });
 }
+
+//火山云视频上传
+export function uploadUserVideo(file,uploadId) {
+  const formData = new FormData();
+  formData.append('file', file);
+  formData.append('uploadId', uploadId)
+  return request({
+    url: '/course/userVideo/uploadUserVideo',
+    method: 'post',
+    data: formData,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  });
+}
+
+// 查询火山云视频上传进度
+export function getUploadProgress(uploadId) {
+  return request({
+    url: '/course/userVideo/uploadProgress',
+    method: 'get',
+    params: { uploadId }
+  });
+}
+
+export function HsyAssumeRoleService() {
+  return request({
+    url: '/course/userVideo/HsyAssumeRoleService',
+    method: 'get',
+  });
+}
+
+
+

+ 92 - 0
src/utils/hsy.js

@@ -0,0 +1,92 @@
+import TTUploader from 'tt-uploader'
+import { HsyAssumeRoleService } from '@/api/course/userVideo'
+const  spaceName = process.env.VUE_APP_HSY_SPACE
+export const uploadToHSY = async (file, onProgress, type, callBackUp) => {
+  try {
+    const res = await HsyAssumeRoleService()
+    //console.log('火山云 STS 凭证:', res)
+    const credentials = res.data.result.credentials
+    //console.log('火山云 credentials 凭证:', credentials)
+
+    if (!credentials) {
+      throw new Error('未获取到火山云 STS 凭证')
+    }
+
+    const uploader = new TTUploader({
+      appId: '917052',
+      userId: '68185444',
+      videoConfig: {
+        spaceName: spaceName,
+      }
+    })
+
+    const date = new Date();
+    const yyyy = date.getFullYear();
+    const MM = String(date.getMonth() + 1).padStart(2, '0');
+    const dd = String(date.getDate()).padStart(2, '0');
+    const datePath = `${yyyy}${MM}${dd}`;
+
+
+    const fileName = `${Date.now()}.mp4`;
+
+    const remoteFileName = `course/${datePath}/${fileName}`;
+
+    const fileKey = uploader.addFile({
+      file,
+      type: 'video',
+      fileName:remoteFileName,
+      stsToken: {
+        CurrentTime: credentials.currentTime,
+        ExpiredTime: credentials.expiredTime,
+        SessionToken: credentials.sessionToken,
+        AccessKeyID: credentials.accessKeyId,
+        SecretAccessKey: credentials.secretAccessKey,
+      },
+    })
+
+    return new Promise((resolve, reject) => {
+
+      // 上传进度
+      uploader.on('progress', (info) => {
+        onProgress && onProgress({
+          percent: info.percent,
+        })
+      })
+
+      // 上传完成
+      uploader.on('complete', (info) => {
+        resolve({
+          ...info.uploadResult,
+          fileKey,
+        })
+      })
+
+      // 上传失败
+      uploader.on('error', (info) => {
+        reject(info)
+      })
+
+      // 取消上传支持
+      if (callBackUp) {
+        callBackUp({
+          uploader,
+          fileKey,
+          cancel: () => {
+            try {
+              uploader.removeFile(fileKey)
+              reject(new Error('Upload cancelled by user'))
+            } catch (e) {
+              reject(e)
+            }
+          }
+        })
+      }
+
+      uploader.start(fileKey)
+    })
+
+  } catch (error) {
+    console.error('火山云上传失败:', error)
+    throw error
+  }
+}

+ 121 - 30
src/views/course/videoResource/index.vue

@@ -774,6 +774,7 @@ import {getByIds, listCourseQuestionBank} from '@/api/course/courseQuestionBank'
 import {getThumbnail} from "@/api/course/userVideo";
 import {uploadObject} from "@/utils/cos.js";
 import {uploadToOBS} from "@/utils/obs.js";
+import {uploadToHSY} from "@/utils/hsy.js";
 import MinimizableDialog from "@/components/MinimizableDialog"
 
 export default {
@@ -1299,37 +1300,95 @@ export default {
       }
     },
     //上传华为云Obs
-    async uploadVideoToHwObs(file, form, onProgress) {
+    // async uploadVideoToHwObs(file, form, onProgress) {
+    //   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, total: progress, lengthComputable: true };
+    //       onProgress(progressEvent);
+    //     }, 1, (uploadInfo) => {
+    //       if (form.tempId) {
+    //         const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
+    //         tokens.obs = uploadInfo.cancel;
+    //         this.uploadCancellationTokens.set(form.tempId, tokens);
+    //       }
+    //     });
+    //
+    //     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) {
+    //     // 更新线路2状态为失败
+    //     this.updateUploadProgress('line2Status', 'failed');
+    //     this.$message.error("线路二上传失败");
+    //     return { success: false, error: error.message };
+    //   }
+    // },
+
+    async uploadVideoToHsy(file, form, onProgress) {
       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, total: progress, lengthComputable: true };
-          onProgress(progressEvent);
-        }, 1, (uploadInfo) => {
-          if (form.tempId) {
-            const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
-            tokens.obs = uploadInfo.cancel;
-            this.uploadCancellationTokens.set(form.tempId, tokens);
-          }
-        });
+        const data = await uploadToHSY(
+          file,
+          (progress) => {
+            // 火山云的进度是小数0-1
+            if (typeof progress.percent === 'number') {
+              const percent = Math.floor(progress.percent * 100);
+
+              // 更新线路2进度
+              this.updateUploadProgress('line2', percent);
+
+              // 对外统一 progress 事件(模拟 xhr)
+              onProgress?.({
+                percent,
+                loaded: percent,
+                total: 100,
+                lengthComputable: true
+              });
+            }
 
-        form.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
+            // 状态同步(成功 / 失败)
+            if (progress.status === 'success') {
+              this.updateUploadProgress('line2Status', 'success');
+              this.updateUploadProgress('line2', 100);
+            }
 
-        // 更新线路2状态为成功
-        this.updateUploadProgress('line2Status', 'success');
-        this.updateUploadProgress('line2', 100);
+            if (progress.status === 'failed') {
+              this.updateUploadProgress('line2Status', 'failed');
+            }
+          },
+          1,
+          (uploadInfo) => {
+            if (form.tempId) {
+              const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
+              tokens.hsy = uploadInfo.cancel;
+              this.uploadCancellationTokens.set(form.tempId, tokens);
+            }
+          }
+        );
+        console.log("上传火山云返回参数",data)
 
-        this.$message.success("线路二上传成功");
+        form.line2 = `${process.env.VUE_APP_VIDEO_URL}/${data.SourceInfo.FileName}`;
+        this.form.hsyVid = data.Vid
+        this.form.hsyVodUrl = process.env.VUE_APP_VIDEO_URL+"/"+data.SourceInfo.FileName
+        console.log("this.form",this.form)
+        this.$message.success('线路二上传成功');
         return { success: true, url: form.line2 };
+
       } catch (error) {
-        // 更新线路2状态为失败
         this.updateUploadProgress('line2Status', 'failed');
-        this.$message.error("线路二上传失败");
-        return { success: false, error: error.message };
+        this.$message.error('线路二上传失败');
+        return { success: false, error: error?.message || 'upload failed' };
       }
     },
     // 更新上传进度的辅助方法
@@ -1366,7 +1425,8 @@ export default {
         await this.getFirstThumbnail(file, this.form);
         const [line1Result, line2Result] = await Promise.allSettled([
           this.uploadVideoToTxPcdn(file, this.form, options.onProgress),
-          this.uploadVideoToHwObs(file, this.form, options.onProgress)
+          // this.uploadVideoToHwObs(file, this.form, options.onProgress)
+          this.uploadVideoToHsy(file, this.form, options.onProgress)
         ]);
 
         const line1Success = line1Result.status === 'fulfilled' && line1Result.value.success;
@@ -1782,7 +1842,8 @@ export default {
         // 并行上传到两个服务器
         const [line1Result, line2Result] = await Promise.allSettled([
           this.uploadVideoToTxPcdnBatch(tempVideo.file, tempVideo),
-          this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo)
+          // this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo),
+          this.uploadVideoToHSYBatch(tempVideo.file, tempVideo),
         ]);
 
         // 检查上传结果
@@ -2208,9 +2269,33 @@ export default {
       }
     },
     // 批量上传 - 华为云
-    async uploadVideoToHwObsBatch(file, tempVideo) {
+    // async uploadVideoToHwObsBatch(file, tempVideo) {
+    //   try {
+    //     const data = await uploadToOBS(file, (progress) => {
+    //       const progressPercent = Math.floor(progress);
+    //       const index = this.videoList.findIndex(item => item.tempId === tempVideo.tempId);
+    //       if (index !== -1) {
+    //         this.videoList[index].uploadDetails.line2 = progressPercent;
+    //         this.videoList[index].uploadDetails.line2Status = 'uploading';
+    //         this.updateBatchProgress(index);
+    //       }
+    //     }, 1, (uploadInfo) => {
+    //       const tokens = this.uploadCancellationTokens.get(tempVideo.tempId) || {};
+    //       tokens.obs = uploadInfo.cancel;
+    //       this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
+    //     });
+    //
+    //     tempVideo.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
+    //     return { success: true, url: tempVideo.line2 };
+    //   } catch (error) {
+    //     return { success: false, error: error.message };
+    //   }
+    // },
+    // 更新批量上传的总进度
+
+    async uploadVideoToHSYBatch(file, tempVideo) {
       try {
-        const data = await uploadToOBS(file, (progress) => {
+        const data = await uploadToHSY(file, (progress) => {
           const progressPercent = Math.floor(progress);
           const index = this.videoList.findIndex(item => item.tempId === tempVideo.tempId);
           if (index !== -1) {
@@ -2223,14 +2308,15 @@ export default {
           tokens.obs = uploadInfo.cancel;
           this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
         });
+        console.log("批量上传返回参数",data)
+        tempVideo.line2 = `${process.env.VUE_APP_VIDEO_URL}/${data.SourceInfo.FileName}`;
+        tempVideo.hsyVid = data.Vid;
 
-        tempVideo.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
-        return { success: true, url: tempVideo.line2 };
+        return { success: true, url: tempVideo.line2};
       } catch (error) {
         return { success: false, error: error.message };
       }
     },
-    // 更新批量上传的总进度
     updateBatchProgress(index) {
       if (index >= 0 && index < this.videoList.length) {
         const item = this.videoList[index];
@@ -2354,8 +2440,13 @@ export default {
         }
 
         if (needRetryLine2) {
+          // uploadPromises.push(
+          //   this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo)
+          //     .then(result => ({ line: 'line2', result }))
+          //     .catch(error => ({ line: 'line2', result: { success: false, error: error.message } }))
+          // );
           uploadPromises.push(
-            this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo)
+            this.uploadVideoToHSYBatch(tempVideo.file, tempVideo)
               .then(result => ({ line: 'line2', result }))
               .catch(error => ({ line: 'line2', result: { success: false, error: error.message } }))
           );