liujiaxin 1 週間 前
コミット
1271055e6f
3 ファイル変更251 行追加79 行削除
  1. 3 0
      common/request.js
  2. 248 77
      pages_course/living.vue
  3. 0 2
      pages_shopping/live/goods.vue

+ 3 - 0
common/request.js

@@ -34,6 +34,9 @@ export default class Request {
 		// uni.showLoading({
 		// 	title: '加载中'
 		// });
+		
+		
+		
 		return new Promise((resolve, reject) => {
 			var httpContentType = 'application/x-www-form-urlencoded';
 			if (!path) {

+ 248 - 77
pages_course/living.vue

@@ -78,9 +78,11 @@
 							:show-center-play-btn="false" :http-cache="false" loop @error="videoError"
 							@timeupdate="onVideoTimeUpdate" @loadedmetadata="onVideoMetaLoaded" @pause="onVideoPause"
 							@play="onVideoPlay" @waiting="onVideoWaiting" :enable-play-gesture="false"
-							@dblclick="preventDoubleClick" preload="auto" type="application/x-mpegURL">
+							:play-strategy="1" @dblclick="preventDoubleClick" preload="auto"
+							:enable-stash-buffer="false" :stash-initial-size="0" :stash-max-size="0" :stash-time="0"
+							type="application/x-mpegURL">
 						</video>
-						<view v-if="liveItem.videoUrl&&liveItem.liveType==2" class="time">{{liveItem.totalTime}}
+						<view v-if="liveItem.videoUrl&&liveItem.liveType==2" class="time">{{diffTotalTime}}
 						</view>
 					</view>
 				</view>
@@ -552,12 +554,11 @@
 				scrollTop: 0,
 				isOnload: false,
 				isConnecting: false, // 是否正在连接中
-				previousToken: null,
 				hasInitialized: false,
 
 				liveViewersData: [],
 				liveUserCalled: false, //调用过watchUserList没
-				userRandomColors: {}, // 缓存用户ID -> 随机色的映射
+				userRandomColors: Object.create(null), // 缓存用户ID -> 随机色的映射
 
 				heartBeatRetryCount: 0, // 心跳发送重试次数(避免一次失败就重连)
 				maxHeartBeatRetries: 2, // 心跳最大重试次数
@@ -625,7 +626,7 @@
 				isShowGoods: false,
 				isShowRed: false,
 				lastClickTime: 0,
-				videoRetryCounts: {}, // 记录每个直播间的视频重试次数,格式: { liveId: 次数 }
+				videoRetryCounts: Object.create(null), // 记录每个直播间的视频重试次数,格式: { liveId: 次数 }
 
 				clickDelay: 300, // 300ms内只响应一次点击
 				liveUserTotal: 0,
@@ -650,27 +651,13 @@
 				liveId: null,
 				userinfo: '', //用户信息
 				userData: {},
-
+				diffTotalTime: ''
 			};
 		},
-
-
-		onLoad(options) {
+		async onLoad(options) {
 			if (options.liveId) {
 				this.liveId = options.liveId;
 			}
-			this.getUserInfo()
-			this.previousToken = ('AppToken')
-			this.initTime();
-			this.userinfo = uni.getStorageSync("userInfo")
-			this.userData = uni.getStorageSync("userData")
-
-			console.log("全部参数", options)
-			//获取键盘高度
-			uni.onKeyboardHeightChange(res => {
-				this.keyboardHeight = res.height * 2;
-			});
-
 			// 扫码传来的参数
 			if (options.scene) {
 				this.scene = options.scene;
@@ -688,19 +675,35 @@
 			if (options.companyId && options.companyUserId) {
 				this.qrFrom = `&companyId=${options.companyId}&companyUserId=${options.companyUserId}`;
 			}
+			this.userinfo = uni.getStorageSync("userInfo")
+			this.userData = uni.getStorageSync("userData")
+			console.log("全部参数", options)
 
-			// 初始化直播间列表
-			this.$nextTick(() => {
-				if (this.liveId) {
-					this.getliving(this.liveId);
-					this.isOnload = true
-					this.getLiveMsg(this.liveItem);
-					this.getliveViewData(this.liveItem);
+			try {
+				const isLogin = await this.utils.isLogin();
+				if (isLogin) {
+					await this.getUserInfo();
+					this.initTime();
 
-				} else {
-					console.error("直播间 ID(liveId)未获取到");
+					if (this.liveId) {
+						// 先获取直播间信息
+						await this.getliving(this.liveId);
+						this.isOnload = true;
+
+						// 然后获取聊天记录
+						await this.getLiveMsg(this.liveId);
+						await this.getliveViewData(this.liveItem);
+					}
 				}
-			})
+			} catch (error) {
+				console.error("初始化失败:", error);
+			}
+			//获取键盘高度
+			uni.onKeyboardHeightChange(res => {
+				this.keyboardHeight = res.height * 2;
+			});
+
+
 		},
 		onPullDownRefresh() {
 			this.getLiveMsg(this.liveId)
@@ -720,7 +723,6 @@
 				await this.getUserInfo()
 			}
 			this.uuId = generateRandomString(16)
-			this.previousToken = await uni.getStorageSync('AppToken')
 			const isLiveLogin = uni.getStorageSync('isLiveLogin')
 			this.share = uni.getStorageSync('share')
 			this.scene = uni.getStorageSync('scene')
@@ -835,12 +837,12 @@
 			if (videoContext) {
 				videoContext.pause();
 			}
-			 // 清理大数据
-			  this.talklist = [];
-			  this.liveViewersData = [];
-			  this.liveViewers = [];
-			  this.products = [];
-			  this.liveItem=[];
+			// 清理大数据
+			this.talklist = [];
+			this.liveViewersData = [];
+			this.liveViewers = [];
+			this.products = [];
+			this.liveItem = [];
 		},
 
 		mounted() {
@@ -875,6 +877,152 @@
 			}
 		},
 		methods: {
+			// 定期清理视频缓存
+			startVideoCacheCleanup() {
+				if (this.videoCleanupTimer) {
+					clearInterval(this.videoCleanupTimer);
+				}
+
+				// 每30秒清理一次视频缓存
+				this.videoCleanupTimer = setInterval(() => {
+					this.cleanupVideoCache();
+				}, 30000);
+			},
+			// 清理视频缓存
+			cleanupVideoCache() {
+				if (!this.liveItem || !this.liveId) return;
+
+				// 只对录播视频进行清理
+				if (this.liveItem.liveType === 2 && this.liveItem.videoUrl) {
+					this.reloadVideoPlayer();
+				}
+			},
+			// 重新加载视频播放器
+			reloadVideoPlayer() {
+				const videoId = `myVideo_${this.liveId}`;
+				const videoContext = uni.createVideoContext(videoId, this);
+
+				if (videoContext) {
+					const currentTime = this.videoCurrentTime;
+
+					// 暂停视频
+					videoContext.pause();
+
+					// 延迟重新加载
+					setTimeout(() => {
+						// 重新设置视频源,强制清理缓存
+						this.$set(this.liveItem, 'videoUrl', this.liveItem.videoUrl + '&t=' + Date.now());
+
+						// 恢复播放位置
+						setTimeout(() => {
+							if (videoContext.seek) {
+								videoContext.seek(currentTime);
+							}
+							videoContext.play();
+						}, 500);
+					}, 100);
+				}
+			},
+			// 启动内存监控
+			startMemoryMonitoring() {
+				if (this.memoryMonitorTimer) {
+					clearInterval(this.memoryMonitorTimer);
+				}
+
+				this.memoryMonitorTimer = setInterval(() => {
+					this.checkMemoryUsage();
+				}, 15000); // 每15秒检查一次
+			},
+			// 检查内存使用情况
+			checkMemoryUsage() {
+				// 在微信小程序中,可以通过性能监控API检查内存
+				if (wx && wx.getPerformance) {
+					try {
+						const performance = wx.getPerformance();
+						const memory = performance.memory;
+
+						if (memory && memory.usedJSHeapSize > 50 * 1024 * 1024) { // 超过50MB
+							console.warn('内存使用过高,触发清理:', memory.usedJSHeapSize);
+							this.forceMemoryCleanup();
+						}
+					} catch (e) {
+						console.log('无法获取内存信息');
+					}
+				}
+			},
+			// 强制内存清理
+			forceMemoryCleanup() {
+				console.log('执行强制内存清理');
+
+				// 1. 清理视频播放器
+				this.cleanupVideoPlayer();
+
+				// 2. 清理大数据
+				this.clearBigData();
+
+				// 3. 强制垃圾回收(在支持的环境下)
+				this.triggerGarbageCollection();
+			},
+			// 清理视频播放器
+			cleanupVideoPlayer() {
+				const videoId = `myVideo_${this.liveId}`;
+				const videoContext = uni.createVideoContext(videoId, this);
+
+				if (videoContext) {
+					// 停止播放
+					videoContext.stop();
+
+					// 重置视频源
+					setTimeout(() => {
+						this.$set(this.liveItem, 'videoUrl', '');
+						setTimeout(() => {
+							this.$set(this.liveItem, 'videoUrl', this.getFreshVideoUrl());
+							this.playVideo();
+						}, 500);
+					}, 100);
+				}
+			},
+			// 获取带时间戳的新视频URL
+			getFreshVideoUrl() {
+				if (!this.liveItem.originalVideoUrl) {
+					this.liveItem.originalVideoUrl = this.liveItem.videoUrl;
+				}
+
+				// 添加时间戳参数,避免缓存
+				const separator = this.liveItem.originalVideoUrl.includes('?') ? '&' : '?';
+				return this.liveItem.originalVideoUrl + separator + 't=' + Date.now();
+			},
+			// 清理大数据
+			clearBigData() {
+				// 清理聊天记录,只保留最近50条
+				if (this.talklist.length > 50) {
+					this.talklist = this.talklist.slice(-50);
+				}
+
+				// 清理观众数据
+				if (this.liveViewersData.length > 100) {
+					this.liveViewersData = this.liveViewersData.slice(-100);
+				}
+
+				// 清理虚拟数据
+				if (this.liveViewers.length > 100) {
+					this.liveViewers = this.liveViewers.slice(-100);
+				}
+
+				// 清理商品数据
+				if (this.products.length > 50) {
+					this.products = this.products.slice(0, 50);
+				}
+			},
+			// 触发垃圾回收(在支持的环境下)
+			triggerGarbageCollection() {
+				if (wx && wx.triggerGC) {
+					wx.triggerGC();
+				}
+			},
+
+
+
 			goMiniProgram() {
 				// uni.navigateToMiniProgram({
 				// 	appId: 'wx45cf09091aead547',
@@ -900,6 +1048,10 @@
 
 			// 清理所有定时器
 			clearAllTimers() {
+				if (this.scrollTimer) {
+					clearTimeout(this.scrollTimer);
+					this.scrollTimer = null;
+				}
 				if (this.liveViewDataTimer) {
 					clearInterval(this.liveViewDataTimer);
 					this.liveViewDataTimer = null;
@@ -1022,20 +1174,24 @@
 				internetTraffic(param)
 			},
 			scrollToBottom() {
-				this.$nextTick(() => {
-					setTimeout(() => {
+				if (this.scrollTimer) {
+					clearTimeout(this.scrollTimer);
+				}
+
+				this.scrollTimer = setTimeout(() => {
+					this.$nextTick(() => {
 						const query = uni.createSelectorQuery().in(this);
-						// 获取 scroll-view 和内容的高度
 						query.select('.scrolly').boundingClientRect(scrollRect => {
+							if (!scrollRect) return;
+
 							query.select('.scrolly').scrollOffset(scrollOffset => {
-								// 计算新的滚动位置
 								const newScrollTop = scrollOffset.scrollHeight - scrollRect
 									.height;
 								this.scrollTop = newScrollTop;
 							}).exec();
 						}).exec();
-					}, 100);
-				});
+					});
+				}, 0);
 			},
 			// 恢复页面活动
 			async resumePageActivity() {
@@ -1353,8 +1509,8 @@
 			onVideoTimeUpdate(e) {
 				// 获取当前播放时间
 				this.videoCurrentTime = e.detail.currentTime;
-				// 每隔5秒保存一次进度(避免频繁存储)
-				if (Math.floor(this.videoCurrentTime) % 5 === 0) {
+				// 每隔10秒保存一次进度(避免频繁存储)
+				if (Math.floor(this.videoCurrentTime) % 10 === 0) {
 					this.saveVideoProgress();
 				}
 				// this.setVideoProgress();
@@ -1450,15 +1606,13 @@
 					.catch(rej => {});
 			},
 
-
 			// 我的中奖名单
 			getMyLottery() {
 				this.winning = true
 				myLottery().then(res => {
 						if (res.code == 200) {
-							console.log("我的中奖名单", res)
+							// console.log("我的中奖名单", res)
 							this.prizeAll = res.data.list || {};
-
 						} else {
 
 						}
@@ -1655,9 +1809,9 @@
 				const hours = this.padZero(Math.floor(totalSeconds / 3600));
 				const minutes = this.padZero(Math.floor((totalSeconds % 3600) / 60));
 				const seconds = this.padZero(totalSeconds % 60);
-				this.$set(this.liveItem, "totalTime", `${hours}:${minutes}:${seconds}`);
+				this.diffTotalTime = `${hours}:${minutes}:${seconds}`;
 				// this.$set(this.liveItem, "diffMs", diffMs);
-				this.$set(this.liveItem, "totalSeconds", totalSeconds);
+				// this.$set(this.liveItem, "totalSeconds", totalSeconds);
 			},
 
 			padZero(num) {
@@ -1795,7 +1949,7 @@
 					const query = uni.createSelectorQuery().in(this);
 					query.select('.view-box').boundingClientRect(data => {
 						if (data) {
-							this.scrollHeight = data.height - 80 ; // 80是标题高度,120是底部高度
+							this.scrollHeight = data.height - 80; // 80是标题高度,120是底部高度
 						}
 					}).exec();
 				});
@@ -2064,7 +2218,6 @@
 			//直播间点赞、关注、在线人数数据
 			getliveViewData(liveItem) {
 				if (!liveItem || !this.liveId) return;
-
 				getLiveViewData(this.liveId).then(res => {
 					if (res.code == 200) {
 						// 强制响应式更新,确保数据实时显示
@@ -2331,6 +2484,25 @@
 					seconds: formatNum(seconds)
 				};
 			},
+			// 限制聊天消息数量,防止内存泄漏
+			addToTalkList(message) {
+				const MAX_TALK_ITEMS = 50;
+
+				const oldList = Array.isArray(this.talklist) ? this.talklist : [];
+				const newList = [...oldList, message];
+
+				if (newList.length > MAX_TALK_ITEMS) {
+					newList.splice(0, newList.length - MAX_TALK_ITEMS);
+				}
+
+				this.talklist = newList;
+
+				// 使用 setTimeout 替代 requestAnimationFrame
+				setTimeout(() => {
+					this.scrollToBottom();
+				}, 0);
+			},
+
 			// 处理Socket消息
 			async handleSocketMessage(message) {
 				let data = JSON.parse(message.data)
@@ -2349,15 +2521,10 @@
 								title: '连接已断开,正在重试...',
 								icon: 'none'
 							});
-							this.handleReconnect(); // 主动触发重连
+							this.handleReconnect();
 							return;
 						}
-						const oldList = Array.isArray(this.talklist) ? this.talklist : [];
-						const newList = [...oldList, messageData];
-						this.talklist = newList;
-						// 1. 将消息追加到当前直播间的talklist中(响应式更新)
-						this.talklist = newList;
-						this.scrollToBottom();
+						this.addToTalkList(messageData);
 					} else if (socketMessage.cmd == 'red') {
 						const redData = socketMessage.data ? JSON.parse(socketMessage.data) : {};
 						this.redInfo = redData || {};
@@ -2482,11 +2649,7 @@
 							this.redTimer = null;
 						}
 						//  请求最新直播间数据
-						await this.getliving(this.liveId); // 注意:需用 await 确保数据更新完成
-
-						//  强制触发视图更新(兜底方案,若上述步骤仍不生效)
-						// this.$forceUpdate(); 
-
+						await this.getliving(this.liveId);
 					} else if (socketMessage.cmd == 'Integral') {
 						this.integral = {
 							msg: socketMessage.msg,
@@ -2521,12 +2684,12 @@
 				}
 			},
 			sendMsg(retries = 1) {
-				// 防止连续点击发送两次(短时锁定)
+				// 防止连续点击发送两次(800ms短时锁定)
 				if (this.isSending) return;
 				this.isSending = true;
 				setTimeout(() => {
 					this.isSending = false;
-				}, 800); // 800ms 内禁止再次发送
+				}, 800);
 
 				const text = (this.value || '').trim();
 				if (!text) {
@@ -2602,7 +2765,6 @@
 					}
 				}
 			}
-
 		}
 	};
 </script>
@@ -2730,13 +2892,17 @@
 		color: #181818;
 		font-weight: 500;
 	}
-/* 减少重绘和重排 */
-.talk-list, .viewer-item, .message-item {
-    will-change: transform;
-    contain: layout style paint;
-    backface-visibility: hidden;
-    transform: translateZ(0);
-}
+
+	/* 减少重绘和重排 */
+	.talk-list,
+	.viewer-item,
+	.message-item {
+		will-change: transform;
+		contain: layout style paint;
+		backface-visibility: hidden;
+		transform: translateZ(0);
+	}
+
 	.talk-list {
 		will-change: transform; // 提示浏览器优化
 		contain: layout style paint; // 限制渲染范围
@@ -3367,8 +3533,13 @@
 	}
 
 	@keyframes simpleFade {
-		from {opacity: 0;}
-		to {opacity: 1;}
+		from {
+			opacity: 0;
+		}
+
+		to {
+			opacity: 1;
+		}
 	}
 
 	.shop-prompt {

+ 0 - 2
pages_shopping/live/goods.vue

@@ -139,8 +139,6 @@
 					icon: "none"
 				})
 			}
-		},
-		mounted() {
 			this.getliveGoods()
 		},
 		methods: {