Browse Source

视频内容bug修复

wengan01 2 tuần trước cách đây
mục cha
commit
e8dbb00ee1
1 tập tin đã thay đổi với 46 bổ sung và 51 xóa
  1. 46 51
      src/views/system/physical/videoContent/index.vue

+ 46 - 51
src/views/system/physical/videoContent/index.vue

@@ -311,7 +311,7 @@ import { ref, reactive, onMounted, getCurrentInstance, type ComponentInternalIns
 import { ElMessageBox } from 'element-plus';
 import request from '@/utils/request';
 
-import { listVideoContent, getVideoContent, delVideoContent, updateVideoContent } from '@/api/system/physical/videoContent';
+import { listVideoContent, getVideoContent, delVideoContent, updateVideoContent, addVideoContent } from '@/api/system/physical/videoContent';
 import type { VideoContentVO, VideoContentForm, VideoContentQuery } from '@/api/system/physical/videoContent/types';
 import { selectEnabledTabsByCategoryList } from '@/api/system/physical/serviceTab';
 import type { ServiceTabVO } from '@/api/system/physical/serviceTab/types';
@@ -425,7 +425,7 @@ const startPolling = (videoId: number | string) => {
 
   pollTimer.value = window.setInterval(async () => {
     await pollVideoStatus(videoId);
-  }, 1000); // 每秒查询一次
+  }, 3000); // 3秒查询一次(大文件时长提取耗时长,窗口约5分钟)
 };
 
 // ✅ 停止轮询
@@ -446,9 +446,9 @@ const pollVideoStatus = async (videoId: number | string) => {
       method: 'GET'
     });
 
-    if (res.data && res.data.data) {
-      const statusData = res.data.data;
-
+    // 拦截器已解包一层:res 即 R 体,res.data 就是状态 VO(原来多取一层 .data 导致轮询从不生效)
+    const statusData: any = res.data;
+    if (statusData) {
       // ✅ 更新时长
       if (statusData.durationSeconds !== undefined && statusData.durationSeconds !== null) {
         form.value.durationSeconds = statusData.durationSeconds;
@@ -461,16 +461,16 @@ const pollVideoStatus = async (videoId: number | string) => {
 
       // ⚠️ 不要更新视频URL!只有异步获取时才更新
 
-      // 数据正常或超过30秒停止轮询
-      if (statusData.dataStatus === '正常' || pollCount.value >= 30) {
+      // 数据正常或超过100次(约5分钟)停止轮询;还没跑完的靠刷新列表或点「异步获取」兑底
+      if (statusData.dataStatus === '正常' || pollCount.value >= 100) {
         stopPolling();
         await getList(); // 刷新列表
       }
     }
   } catch (error) {
     console.error('轮询查询状态失败:', error);
-    // 如果轮询失败超过30次也停止
-    if (pollCount.value >= 30) {
+    // 如果轮询失败超过100次也停止
+    if (pollCount.value >= 100) {
       stopPolling();
     }
   }
@@ -536,6 +536,9 @@ const handleUpdate = async (row?: VideoContentVO) => {
   Object.assign(form.value, res.data);
   ossVideoUrlPreviewUrl.value = String(res.data?.ossVideoUrl || '');
 
+  // 初始化数据状态:异常行打开编辑时直接显示「异步获取」修复按钮
+  dataStatus.value = Number(form.value.durationSeconds) > 0 && form.value.ossVideoUrl ? '正常' : '异常';
+
   if (res.data.videoCoverUrl) {
     videoCoverUrlFileList.value = [{ name: '已上传封面图', url: res.data.videoCoverUrl, status: 'success' }];
     videoCoverUrlPreviewUrl.value = res.data.videoCoverUrl;
@@ -561,6 +564,17 @@ const submitForm = () => {
       try {
         if (form.value.id) {
           await updateVideoContent(form.value);
+        } else {
+          // 新增模式:按确定时才创建记录并开始后台处理(上传阶段只传OSS不建记录)
+          const addRes = await addVideoContent(form.value);
+          const newId = addRes.data;
+          if (newId) {
+            form.value.id = Number(newId);
+            // 时长还没就绪(大文件异步提取)时启动轮询自动补
+            if (!(Number(form.value.durationSeconds) > 0)) {
+              startPolling(form.value.id);
+            }
+          }
         }
         proxy?.$modal.msgSuccess('操作成功');
         dialog.visible = false;
@@ -733,7 +747,8 @@ const handleOssVideoUrlChange = async (file: any) => {
     if (form.value.videoSeeCount) formData.append('videoSeeCount', String(form.value.videoSeeCount));
     if (form.value.id) formData.append('videoId', String(form.value.id));
 
-    const timeout = Math.max(300000, Math.floor(fileSizeMB * 3000));
+    // 超时:底10分钟 + 每MB 2秒(按上行0.5MB/s估并留4倍余量),2GB≈67分钟
+    const timeout = Math.max(600000, Math.floor(fileSizeMB * 2000));
 
     const uploadRes = await request({
       url: '/physical/videoContent/uploadVideo',
@@ -753,61 +768,41 @@ const handleOssVideoUrlChange = async (file: any) => {
 
     uploading.value = false;
 
-    // ⚠️ 根据核心原则:上传成功后不设置视频URL!
-    // 视频URL只在两个地方设置:1. 修改页面打开时 2. 异步获取成功时
-    // 拦截器已解包一层:uploadRes 即 R 体,uploadRes.data 就是 SysOssVo(原来多取一层 .data 全为 undefined)
+    // 拦截器已解包一层:uploadRes 即 R 体,uploadRes.data 就是 SysOssVo
     const ossData: any = uploadRes.data || {};
-    const videoUrl = ossData.url || ossData.ossVideoUrl;
     const ossId = ossData.ossId;
-    const duration = ossData.duration || ossData.videoDuration;
-    const videoFileName = ossData.videoFileName;
-    const serviceTagName = ossData.serviceTagName;
-
-    // ❌ 删除:不设置视频URL
-    // form.value.ossVideoUrl = videoUrl || localPreviewUrl;
-    // ossVideoUrlPreviewUrl.value = videoTempUrl;
+    const permanentUrl = ossData.url;
+    const duration = ossData.duration;
 
     if (ossId) form.value.ossId = ossId;
-    if (videoFileName) {
-      form.value.videoFileName = videoFileName;
+    // 永久URL:新增模式确定时入库用;编辑模式 updateByBo 会以同值覆盖
+    if (permanentUrl) form.value.ossVideoUrl = permanentUrl;
+    if (ossData.originalName) {
+      form.value.videoFileName = ossData.originalName;
     } else if (fileObj?.name) {
       form.value.videoFileName = fileObj.name;
     }
-    if (serviceTagName) {
-      form.value.serviceTagName = serviceTagName;
-    }
 
-    // 后端把新建视频主键放在 ext1 返回(SysOssVo 无 id 字段),取不到会导致确定时不走整体更新、选视频后改的字段(如所属标签)丢失
-    const newVideoId = ossData.id || ossData.ext1;
-    if (newVideoId) {
-      form.value.id = Number(newVideoId);
+    const finalDuration = duration && !isNaN(duration) && Number(duration) > 0 ? Math.floor(Number(duration)) : 0;
+    if (finalDuration > 0) {
+      form.value.durationSeconds = finalDuration;
+    }
 
+    // 只有编辑模式才回传主键 ext1(记录已存在);新增模式上传不建记录,需按确定才入库
+    const returnedVideoId = ossData.ext1;
+    if (returnedVideoId) {
+      form.value.id = Number(returnedVideoId);
       // ✅ 上传成功后启动轮询(轮询只更新时长和状态,不更新视频URL)
       startPolling(form.value.id);
+      await getList();
     }
 
-    let finalDuration = duration && !isNaN(duration) && Number(duration) > 0 ? Math.floor(Number(duration)) : 0;
-
-    if (!isDurationValid(finalDuration) && form.value.id) {
-      try {
-        const durationRes = await request({
-          url: `/physical/videoContent/getVideoDuration/${form.value.id}`,
-          method: 'GET'
-        });
-        if (durationRes.data && durationRes.data.success && durationRes.data.duration > 0) {
-          finalDuration = durationRes.data.duration;
-        }
-      } catch (durationError) {
-        console.error('调用获取时长接口失败:', durationError);
-      }
-    }
-
-    if (finalDuration > 0) {
-      form.value.durationSeconds = finalDuration;
+    // 提示语与实际链路对齐:≤1GB 时长同步提取;>1GB 才是后台异步提取;同步提取失败时只能靠确定后点「异步获取」从备份表修复
+    let uploadMsg = '视频上传成功!时长已自动获取';
+    if (finalDuration <= 0) {
+      uploadMsg = fileSizeMB > 1024 ? '视频上传成功!时长后台提取中,按确定后自动补齐' : '视频上传成功!但未获取到时长,按确定后如数据状态异常可点「异步获取」从备份表修复';
     }
-
-    proxy?.$modal.msgSuccess('视频上传成功!时长已自动获取');
-    await getList();
+    proxy?.$modal.msgSuccess(uploadMsg);
   } catch (error: any) {
     console.error('视频上传失败:', error);
     uploading.value = false;