guoyu/log/自动更新视频duration-前端代码.md
2025-12-11 23:28:07 +08:00

6.6 KiB
Raw Blame History

自动更新视频duration - 前端实现

后端接口已添加

接口地址: POST /study/courseware/updateDuration

参数:

  • coursewareId: 课件ID
  • duration: 视频时长(秒)

特点:

  • 允许匿名访问(@Anonymous
  • 只更新未配置duration的视频
  • 防止重复覆盖已有的duration

📱 前端调用代码uni-app

方式1在视频加载完成时调用

// 在视频播放页面
<template>
  <view>
    <video 
      :src="videoUrl" 
      @loadedmetadata="onVideoLoaded"
      @timeupdate="onTimeUpdate"
    ></video>
  </view>
</template>

<script>
export default {
  data() {
    return {
      coursewareId: null,  // 从路由参数获取
      videoUrl: '',
      videoDuration: 0,
      durationUpdated: false  // 防止重复调用
    }
  },
  
  onLoad(options) {
    this.coursewareId = options.coursewareId;
    this.videoUrl = options.videoUrl;
  },
  
  methods: {
    // 视频元数据加载完成(可获取时长)
    onVideoLoaded(e) {
      console.log('视频加载完成', e);
      
      // 获取视频时长
      const duration = Math.floor(e.detail.duration);
      this.videoDuration = duration;
      
      console.log('视频时长:', duration, '秒');
      
      // 自动更新到后端
      if (!this.durationUpdated && duration > 0) {
        this.updateVideoDuration(duration);
      }
    },
    
    // 或者在第一次播放位置更新时调用
    onTimeUpdate(e) {
      // 只在第一次调用
      if (!this.durationUpdated && e.detail.duration > 0) {
        const duration = Math.floor(e.detail.duration);
        this.videoDuration = duration;
        this.updateVideoDuration(duration);
      }
    },
    
    // 调用后端接口更新duration
    updateVideoDuration(duration) {
      if (this.durationUpdated) return;
      
      this.$http.post('/study/courseware/updateDuration', {
        coursewareId: this.coursewareId,
        duration: duration
      }).then(res => {
        if (res.code === 200) {
          console.log('✅ duration更新成功:', duration, '秒');
          this.durationUpdated = true;
        } else {
          console.log(' duration响应:', res.msg);
        }
      }).catch(err => {
        console.error('❌ duration更新失败:', err);
      });
    }
  }
}
</script>

方式2使用uni.createVideoContext

// 在mounted或onReady中
onReady() {
  // 创建video上下文
  this.videoContext = uni.createVideoContext('myVideo', this);
  
  // 延迟获取视频信息(等待加载)
  setTimeout(() => {
    this.getVideoDuration();
  }, 1000);
},

methods: {
  getVideoDuration() {
    // 注意uni-app的video组件可能需要通过事件获取duration
    // 推荐使用 @loadedmetadata 事件方式1
  }
}

方式3直接使用HTML5 Video APIH5页面

<video 
  id="myVideo" 
  :src="videoUrl"
  @loadedmetadata="handleLoadedMetadata"
></video>

<script>
export default {
  methods: {
    handleLoadedMetadata(event) {
      const video = event.target;
      const duration = Math.floor(video.duration);
      
      console.log('视频时长:', duration);
      
      // 调用后端更新
      this.updateDuration(duration);
    },
    
    updateDuration(duration) {
      fetch('/study/courseware/updateDuration', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          coursewareId: this.coursewareId,
          duration: duration
        })
      })
      .then(res => res.json())
      .then(data => {
        console.log('更新结果:', data);
      });
    }
  }
}
</script>

🔧 集成步骤

步骤1后端编译部署

cd Study-Vue-redis
mvn clean package -DskipTests

# 重启服务
java -jar ry-study-admin/target/ry-study-admin.jar

步骤2前端代码修改

找到视频播放页面: fronted_uniapp/pages/study/video.vue (或类似文件)

添加以下代码:

  1. <video> 标签添加事件监听:
<video @loadedmetadata="onVideoLoaded"></video>
  1. methods 中添加方法:
onVideoLoaded(e) {
  const duration = Math.floor(e.detail.duration);
  if (duration > 0) {
    this.updateVideoDuration(duration);
  }
},

updateVideoDuration(duration) {
  this.$http.post('/study/courseware/updateDuration', {
    coursewareId: this.coursewareId,
    duration: duration
  }).then(res => {
    console.log('duration更新:', res.msg);
  });
}

步骤3测试验证

  1. 打开APP观看一个视频
  2. 查看控制台日志:应该显示"duration更新成功"
  3. 查看数据库
SELECT id, title, duration 
FROM courseware 
WHERE type = 'video' AND duration IS NOT NULL;
  1. 再次观看同一视频:应该显示"duration已存在无需更新"

📊 预期效果

首次观看视频:

前端:加载视频 → 获取时长300秒 → 调用接口
后端:接收请求 → 检查duration为NULL → 更新为300秒 → 返回成功
日志:✅ 自动更新视频duration: 课件ID=123, 时长=300秒

再次观看视频:

前端:加载视频 → 获取时长300秒 → 调用接口
后端:接收请求 → 检查duration已存在 → 跳过更新 → 返回"无需更新"

几天后效果:

-- 查询已自动更新的视频
SELECT COUNT(*) FROM courseware 
WHERE type = 'video' AND duration IS NOT NULL;

-- 预期结果随着用户观看越来越多视频会自动补充duration
-- 初始: 0个
-- 一周后: 100+个
-- 一个月后: 大部分常看的视频都有了

优点

  1. 无需批量处理 - 自动渐进式更新
  2. 用户无感知 - 后台静默完成
  3. 准确可靠 - 真实视频播放器获取的时长
  4. 性能友好 - 只更新一次,不重复
  5. 自然覆盖 - 常看的视频优先更新

🎯 完整流程

用户打开视频
    ↓
前端加载视频
    ↓
loadedmetadata事件触发
    ↓
获取 video.duration
    ↓
调用后端接口
    ↓
后端检查并更新数据库
    ↓
完成视频有了duration
    ↓
下次计算进度时使用精确的95%标准

📝 注意事项

  1. 确保视频能正常加载 - 如果视频加载失败无法获取duration
  2. 网络请求不阻塞播放 - 接口调用是异步的
  3. 接口调用失败不影响观看 - 有try-catch保护
  4. 已有duration的不会被覆盖 - 防止误操作

所有代码已准备好,编译部署即可使用!