guoyu/log/自动更新视频duration-前端代码.md

301 lines
6.6 KiB
Markdown
Raw Normal View History

2025-12-11 23:28:07 +08:00
# 自动更新视频duration - 前端实现
## ✅ **后端接口已添加**
**接口地址:** `POST /study/courseware/updateDuration`
**参数:**
- `coursewareId`: 课件ID
- `duration`: 视频时长(秒)
**特点:**
- ✅ 允许匿名访问(`@Anonymous`
- ✅ 只更新未配置duration的视频
- ✅ 防止重复覆盖已有的duration
---
## 📱 **前端调用代码uni-app**
### **方式1在视频加载完成时调用**
```javascript
// 在视频播放页面
<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**
```javascript
// 在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页面**
```javascript
<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后端编译部署**
```bash
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>` 标签添加事件监听:
```html
<video @loadedmetadata="onVideoLoaded"></video>
```
2.`methods` 中添加方法:
```javascript
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. **查看数据库**
```sql
SELECT id, title, duration
FROM courseware
WHERE type = 'video' AND duration IS NOT NULL;
```
4. **再次观看同一视频**:应该显示"duration已存在无需更新"
---
## 📊 **预期效果**
### **首次观看视频:**
```
前端:加载视频 → 获取时长300秒 → 调用接口
后端:接收请求 → 检查duration为NULL → 更新为300秒 → 返回成功
日志:✅ 自动更新视频duration: 课件ID=123, 时长=300秒
```
### **再次观看视频:**
```
前端:加载视频 → 获取时长300秒 → 调用接口
后端:接收请求 → 检查duration已存在 → 跳过更新 → 返回"无需更新"
```
### **几天后效果:**
```sql
-- 查询已自动更新的视频
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的不会被覆盖** - 防止误操作
**所有代码已准备好,编译部署即可使用!** ✨