/** * 视频控制模块 * 负责所有视频播放相关的逻辑 */ import { campApi } from '../../../config/camp_api.js'; import { resolveVideoCompletionPercent } from './utils.js'; import * as dataFetcher from './data-fetcher.js'; /** * 视频播放结束 * @param {Object} context - 页面上下文 */ export function onVideoEnded(context) { context.setData({ isVideoTaskPlaying: false }); } /** * 视频播放错误 * @param {Object} context - 页面上下文 */ export function onVideoError(context) { context.setData({ showVideo: false, isVideoTaskPlaying: false }); wx.showToast({ title: '视频播放失败', icon: 'none' }); } /** * 视频开始播放 * 区分任务视频和介绍视频:只有视频任务才标记 isVideoTaskPlaying * @param {Object} context - 页面上下文 */ export function onVideoPlay(context) { var isTaskVideo = !!context.data.currentPlayingTaskId; context.setData({ hasVideoPlayed: true, isAutoPlay: false, _pendingVideoPlay: false, isVideoTaskPlaying: isTaskVideo // 只有视频任务才标记为 true }); } /** * 视频暂停 * @param {Object} context - 页面上下文 */ export function onVideoPause(context) { context.setData({ isVideoTaskPlaying: false }); } /** * 监听视频播放进度 请求接口 * @param {Object} context - 页面上下文 * @param {Object} e - 事件对象 */ export async function onVideoTimeUpdate(context, e) { var currentVideoCompletionPercent = context.data.currentVideoCompletionPercent; var hasLogged10Percent = context.data.hasLogged10Percent; var currentPlayingTaskId = context.data.currentPlayingTaskId; var currentSelectedCourseId = context.data.currentSelectedCourseId; var currentSelectedCourseIndex = context.data.currentSelectedCourseIndex; var requiredPercent = 100; if (typeof currentVideoCompletionPercent === 'number' && !isNaN(currentVideoCompletionPercent) && currentVideoCompletionPercent > 0) { requiredPercent = currentVideoCompletionPercent; } if (requiredPercent <= 0) { requiredPercent = 100; } if (requiredPercent > 100) { requiredPercent = 100; } if (requiredPercent > 0 && requiredPercent <= 1) { requiredPercent = requiredPercent * 100; } var persent = requiredPercent / 100; var { currentTime, duration } = e.detail; // 检查是否已经发送过请求 if (hasLogged10Percent) { return; } // 检查是否达到进度要求或视频结束 var isProgressReached = duration > 0 && currentTime / duration >= persent; var isVideoEnded = duration > 0 && currentTime >= duration; if ((isProgressReached || isVideoEnded) && currentPlayingTaskId) { var userId = String(wx.getStorageSync('wxuserid') || ''); var taskId = String(currentPlayingTaskId || ''); if (!userId) { return; } if (!taskId) { return; } try { var payload = { user_id: userId, task_id: taskId, is_completed: true, completed_at: String(Math.floor(Date.now() / 1000)) }; var res = await campApi.updateCampProgress(payload); if ((res && res.success === true) || (res && res.code === 200)) { // 先立即更新任务状态(立即更新UI),不中断视频播放 if (context.updateTaskStatus) { context.updateTaskStatus(taskId, 'Completed'); } // 视频任务进度已上报成功,静默请求一次营地详情接口,拉取最新任务列表与 can_start,下一任务可解锁 var campId = context.data.campId; if (campId && dataFetcher.fetchCampData) { dataFetcher.fetchCampData(context, campId, true); } else if (context.refreshTaskListStatus) { context.refreshTaskListStatus(currentSelectedCourseId, currentSelectedCourseIndex, true); } } } catch (error) { } // 标记已发送请求 context.setData({ hasLogged10Percent: true }); } } /** * 处理视频任务 * 注意:无论任务是否已完成,都允许用户观看视频 * @param {Object} context - 页面上下文 * @param {Object} sendParams - 任务参数 */ export function handleVideoTask(context, sendParams) { var taskIdStr = sendParams.taskId ? String(sendParams.taskId) : ''; var completionPercent = resolveVideoCompletionPercent(sendParams.task); var videoCompletionMap = Object.assign({}, context.data.videoCompletionMap || {}); if (completionPercent === null && taskIdStr && videoCompletionMap.hasOwnProperty(taskIdStr)) { completionPercent = videoCompletionMap[taskIdStr]; } // 使用按任务ID查询的新接口(仅保留新结构) // 注意:不检查任务状态,即使任务已完成也允许播放视频 campApi.getTaskDetailById(sendParams.taskId).then(function(res){ var videoUrl = ''; if (!res || res.success !== true || !res.task) { wx.showToast({ title: '获取视频任务失败', icon: 'none' }); wx.hideLoading(); return; } var task = res.task || {}; // 兼容多种格式:task.content.video_url 或 task.content.video.video_url var content = task.content || {}; var videoContent = content.video || {}; videoUrl = content.video_url || videoContent.video_url || ''; var detailPercent = resolveVideoCompletionPercent(task); if (detailPercent !== null) { completionPercent = detailPercent; } if (completionPercent === null) { completionPercent = 100; } if (typeof completionPercent !== 'number' || isNaN(completionPercent)) { completionPercent = 100; } if (completionPercent <= 0) { completionPercent = 100; } completionPercent = Math.min(100, Math.max(1, Math.round(completionPercent))); if (taskIdStr) { videoCompletionMap[taskIdStr] = completionPercent; } if (videoUrl) { // 先暂停当前视频(如果有),避免播放冲突 try { if (context.videoContext) { context.videoContext.pause(); } } catch (e) { } // 准备新的视频数据(注意:不覆盖 introType,保留打卡营原始介绍类型) var newVideoData = { topContent: videoUrl, topContentType: 'INTRO_TYPE_VIDEO', // 注意:不设置 introType,保留打卡营原始的介绍类型,以便退出时正确恢复 showVideo: true, hasLogged10Percent: false, currentPlayingTaskId: sendParams.taskId, currentPlayingTaskType: 'TASK_TYPE_VIDEO', videoTitle: sendParams.taskTitle, isAutoPlay: true, currentVideoCompletionPercent: completionPercent, videoCompletionMap: videoCompletionMap, _pendingVideoPlay: true, // 标记需要自动播放 hasVideoPlayed: false // 重置播放状态 }; // 如果当前已经有视频在播放(比如介绍视频),需要先销毁再重建 video 组件 // 否则微信小程序的