Jelajahi Sumber

后端记录心跳

xw 1 Minggu lalu
induk
melakukan
83f4341ac6
1 mengubah file dengan 154 tambahan dan 2 penghapusan
  1. 154 2
      pages_course/living.vue

+ 154 - 2
pages_course/living.vue

@@ -817,6 +817,13 @@
 				errorCount: 0, // 错误计数
 				lastPerformanceCheck: 0, // 上次性能检查时间
 
+				// 观看时长统计相关
+				watchStartTime: 0, // 观看开始时间(毫秒时间戳)
+				accumulatedWatchDuration: 0, // 累计观看时长(秒)
+				isPageVisible: true, // 页面是否可见
+				lastPauseTime: 0, // 上次暂停时间
+				watchDurationTimer: null, // 观看时长计时器
+
 				stayTime: 0,
 				startTime: 0,
 
@@ -1156,6 +1163,12 @@
 			// }
 			// 恢复播放和连接
 			await this.resumePageActivity();
+			
+			// 恢复观看时长统计(如果之前已经开始统计)
+			if (this.watchStartTime > 0 || this.accumulatedWatchDuration > 0) {
+				this.resumeWatchDurationTracking();
+			}
+			
 			// this.userinfo = JSON.parse(uni.getStorageSync('userInfo'));
 			this.userinfo = uni.getStorageSync('userinfo');
 			this.isAgreement = uni.getStorageSync('isAgreement');
@@ -1339,6 +1352,10 @@
 			//  清除所有定时器(使用增强清理)
 			// this.clearAllTimersEnhanced();
 			// this.stopHeartBeat();
+			
+			// 暂停观看时长统计
+			this.pauseWatchDurationTracking();
+			
 			// 页面隐藏时,提交当前流量数据
 			if (this.videoLoaded && this.trafficStartTime && this.trafficTimer) {
 				const watchDuration = Math.floor((Date.now() - this.trafficStartTime) / 1000);
@@ -1362,6 +1379,10 @@
 		onUnload() {
 			// 保存视频进度
 			this.saveVideoProgress();
+			
+			// 停止观看时长统计
+			this.stopWatchDurationTracking();
+			
             // 用户退出时,再次请求一次10s流量接口
 			if (this.videoLoaded && this.trafficStartTime) {
 				const watchDuration = Math.floor((Date.now() - this.trafficStartTime) / 1000);
@@ -1487,6 +1508,124 @@
 			},
 		},
 		methods: {
+			// ======================== 观看时长统计相关方法 ========================
+			/**
+			 * 开始观看时长统计
+			 * WebSocket连接成功后调用
+			 */
+			startWatchDurationTracking() {
+				// 防止重复启动
+				if (this.watchStartTime > 0) {
+					console.log('观看时长统计已启动,跳过');
+					return;
+				}
+
+				this.watchStartTime = Date.now();
+				this.isPageVisible = true;
+				console.log('开始观看时长统计', new Date(this.watchStartTime).toLocaleString());
+
+				// 启动页面可见性监听
+				this.initPageVisibilityListener();
+			},
+
+			/**
+			 * 获取当前累计观看时长(秒)
+			 * @returns {number} 观看时长(秒)
+			 */
+			getCurrentWatchDuration() {
+				if (this.watchStartTime === 0) {
+					return this.accumulatedWatchDuration;
+				}
+
+				// 如果页面可见,计算当前时段的时长
+				if (this.isPageVisible) {
+					const currentDuration = Math.floor((Date.now() - this.watchStartTime) / 1000);
+					return this.accumulatedWatchDuration + currentDuration;
+				}
+
+				// 页面不可见,返回累计时长
+				return this.accumulatedWatchDuration;
+			},
+
+			/**
+			 * 暂停观看时长统计(页面隐藏/后台时)
+			 */
+			pauseWatchDurationTracking() {
+				if (!this.isPageVisible || this.watchStartTime === 0) {
+					return;
+				}
+
+				// 累加本次观看的时长
+				const currentSessionDuration = Math.floor((Date.now() - this.watchStartTime) / 1000);
+				this.accumulatedWatchDuration += currentSessionDuration;
+				this.lastPauseTime = Date.now();
+				this.isPageVisible = false;
+
+				console.log(`暂停观看统计: 本次=${currentSessionDuration}秒, 累计=${this.accumulatedWatchDuration}秒`);
+			},
+
+			/**
+			 * 恢复观看时长统计(页面显示/前台时)
+			 */
+			resumeWatchDurationTracking() {
+				if (this.isPageVisible) {
+					return;
+				}
+
+				// 重新记录开始时间
+				this.watchStartTime = Date.now();
+				this.isPageVisible = true;
+
+				const pauseDuration = this.lastPauseTime > 0 ? Math.floor((Date.now() - this.lastPauseTime) / 1000) : 0;
+				console.log(`恢夏观看统计: 暂停了${pauseDuration}秒, 当前累计=${this.accumulatedWatchDuration}秒`);
+			},
+
+			/**
+			 * 停止观看时长统计
+			 */
+			stopWatchDurationTracking() {
+				if (this.isPageVisible && this.watchStartTime > 0) {
+					const currentSessionDuration = Math.floor((Date.now() - this.watchStartTime) / 1000);
+					this.accumulatedWatchDuration += currentSessionDuration;
+				}
+
+				console.log(`停止观看统计: 总时长=${this.accumulatedWatchDuration}秒`);
+
+				// 重置状态
+				this.watchStartTime = 0;
+				this.isPageVisible = true;
+				this.lastPauseTime = 0;
+
+				// 移除监听
+				this.removePageVisibilityListener();
+			},
+
+			/**
+			 * 初始化页面可见性监听
+			 */
+			initPageVisibilityListener() {
+				// uni-app 的页面生命周期已经在 onShow/onHide 中处理
+				// 这里主要监听小程序的前后台切换
+				uni.onAppShow(() => {
+					console.log('小程序回到前台');
+					this.resumeWatchDurationTracking();
+				});
+
+				uni.onAppHide(() => {
+					console.log('小程序切换到后台');
+					this.pauseWatchDurationTracking();
+				});
+			},
+
+			/**
+			 * 移除页面可见性监听
+			 */
+			removePageVisibilityListener() {
+				// uni-app 不需要手动移除监听,生命周期自动管理
+				console.log('页面可见性监听已移除');
+			},
+
+			// ======================== 以下是原有方法 ========================
 			noticeHeightFun() {
 				const query = uni.createSelectorQuery().in(this);
 				query.select('.notice-message').boundingClientRect(rect => {
@@ -3031,7 +3170,7 @@
 				);
 			},
 
-			//发送心跳
+			//发送心跳(包含观看时长)
 			sendHeartBeat() {
 				if (!this.isSocketAvailable() || !this.isNetworkAvailable) {
 					console.warn('网络不可用或Socket连接异常,跳过心跳发送');
@@ -3039,6 +3178,9 @@
 				}
 				this.lastHeartBeatTime = Date.now();
 
+				// 计算当前累计观看时长
+				const currentWatchDuration = this.getCurrentWatchDuration();
+
 				try {
 					const heartBeatMsg = JSON.stringify({
 						cmd: 'heartbeat',
@@ -3046,12 +3188,14 @@
 						userId: this.userInfo.userId || '',
 						liveId: this.liveId,
 						timestamp: this.lastHeartBeatTime,
-						networkType: this.networkType
+						networkType: this.networkType,
+						data: String(currentWatchDuration)
 					});
 
 					this.socket.send({
 						data: heartBeatMsg,
 						success: () => {
+							console.log(`心跳发送成功: 观看时长=${currentWatchDuration}秒`);
 							this.heartBeatRetryCount = 0; // 成功后重置重试次数
 							this.adjustHeartBeatInterval(true); // 网络良好,可适当延长间隔
 							this.startPingTimeout(); // 启动超时检测
@@ -4496,7 +4640,12 @@
 						} else {
 							console.log(`WebSocket重连成功(第${this.reconnectCount}次尝试)`);
 						}
+						
+						// 启动心跳
 						this.startHeartBeat();
+						
+						// 启动观看时长统计
+						this.startWatchDurationTracking();
 
 					});
 
@@ -4544,6 +4693,9 @@
 						this.isSocketOpen = false;
 						this.isConnecting = false;
 						this.stopHeartBeat(); // 清除心跳定时器
+										
+						// 暂停观看时长统计
+						this.pauseWatchDurationTracking();
 
 						// 根据关闭原因决定是否重连
 						if (!this.isManualClose) {