我想做一个公司内部学习平台,能播放视频,记录学员学习情况,用的是django+mysql+模板这种形式,现在的问题是,视频能播放但是不能拖动进度条,再次进入不能记录上次观看位置。代码如下,学习资料app里的视图函数是material_video_detail,记录app里的相关联函数是:save_video_progress和get_video_progress。网页代码如下,有没有朋友能帮忙解答一下
课程视图层:
@login_required
def material_video_detail(request,material_id):
# 获取资料详情并处理视频播放
material = get_object_or_404(LearningMaterial, pk=material_id)
record, created = LearningRecord.objects.get_or_create(
user=request.user, material=material, defaults={'last_position': 0, 'duration': 0})
return render(request, 'courses/material_video_detail.html', locals())
记录视图层的2个函数:
@login_required
@require_http_methods(["POST"])
def save_video_progress(request, material_id):
material = get_object_or_404(LearningMaterial, id=material_id)
current_time = float(request.POST.get('current_time', 0))
duration = float(request.POST.get('duration', 0))
# 创建或更新记录
record, _ = LearningRecord.objects.update_or_create(
user=request.user,
material=material,
defaults={
'last_position': current_time,
# 'progress': round((current_time / duration) * 100) if duration else 0,
'duration':duration
}
)
record.update_progress(current_time,duration)
if record.is_completed:
record.earned_points=material.points
record.save()
return JsonResponse({'status': 'success'})
@login_required
def get_video_progress(request, material_id):
material = get_object_or_404(LearningMaterial, id=material_id)
record = LearningRecord.objects.filter(
user=request.user,
material=material
).first()
print(record.last_position)
return JsonResponse({
'last_position': record.last_position if record else 0,
'progress': record.progress if record else 0
})
视频播放详细页:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="ratio ratio-16x9">
<video controls class="w-100" id="videoPlayer">
<source src="{{ material.file.url }}"
type="video/mp4">
您的浏览器不支持视频播放
</video>
</div>
<!-- material_video_detail.html -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const video = document.getElementById('videoPlayer');
const materialId = {{ material.id }};
let lastSaveTime = 0;
let hasSetInitialTime = false;
// 1. 优先从接口获取进度
fetch(`/records/get_progress/${materialId}/`)
.then(response => {
if (!response.ok) throw new Error('Network error');
return response.json();
})
.then(data => {
if (data.last_position > 0) {
video.currentTime = data.last_position;
hasSetInitialTime = true;
}
})
.catch(error => console.error('加载进度失败:', error));
// 2. 元数据加载后的备用设置
video.addEventListener('loadedmetadata', () => {
if (!hasSetInitialTime) {
const templatePosition = {{ record.last_position|default:0 }};
video.currentTime = templatePosition;
}
// 确保视频可拖动
video.removeAttribute('controlslist');
});
// 3. 保存进度逻辑(保持不变)
const saveProgress = () => {
if(video.duration > 0 && video.readyState >= 2) {
const now = Date.now();
if(now - lastSaveTime > 5000) {
const formData = new FormData();
formData.append('current_time', video.currentTime);
formData.append('duration', video.duration);
fetch(`/records/progress/${materialId}/`, {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': '{{ csrf_token }}'
}
})
.catch(error => console.error('保存失败:', error));
lastSaveTime = now;
}
}
};
video.addEventListener('timeupdate', saveProgress);
video.addEventListener('seeked', saveProgress);
video.addEventListener('pause', saveProgress);
window.addEventListener('beforeunload', saveProgress);
});
</script>
</body>
</html>