|
@@ -78,9 +78,11 @@
|
|
|
:show-center-play-btn="false" :http-cache="false" loop @error="videoError"
|
|
:show-center-play-btn="false" :http-cache="false" loop @error="videoError"
|
|
|
@timeupdate="onVideoTimeUpdate" @loadedmetadata="onVideoMetaLoaded" @pause="onVideoPause"
|
|
@timeupdate="onVideoTimeUpdate" @loadedmetadata="onVideoMetaLoaded" @pause="onVideoPause"
|
|
|
@play="onVideoPlay" @waiting="onVideoWaiting" :enable-play-gesture="false"
|
|
@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>
|
|
</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>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
@@ -552,12 +554,11 @@
|
|
|
scrollTop: 0,
|
|
scrollTop: 0,
|
|
|
isOnload: false,
|
|
isOnload: false,
|
|
|
isConnecting: false, // 是否正在连接中
|
|
isConnecting: false, // 是否正在连接中
|
|
|
- previousToken: null,
|
|
|
|
|
hasInitialized: false,
|
|
hasInitialized: false,
|
|
|
|
|
|
|
|
liveViewersData: [],
|
|
liveViewersData: [],
|
|
|
liveUserCalled: false, //调用过watchUserList没
|
|
liveUserCalled: false, //调用过watchUserList没
|
|
|
- userRandomColors: {}, // 缓存用户ID -> 随机色的映射
|
|
|
|
|
|
|
+ userRandomColors: Object.create(null), // 缓存用户ID -> 随机色的映射
|
|
|
|
|
|
|
|
heartBeatRetryCount: 0, // 心跳发送重试次数(避免一次失败就重连)
|
|
heartBeatRetryCount: 0, // 心跳发送重试次数(避免一次失败就重连)
|
|
|
maxHeartBeatRetries: 2, // 心跳最大重试次数
|
|
maxHeartBeatRetries: 2, // 心跳最大重试次数
|
|
@@ -625,7 +626,7 @@
|
|
|
isShowGoods: false,
|
|
isShowGoods: false,
|
|
|
isShowRed: false,
|
|
isShowRed: false,
|
|
|
lastClickTime: 0,
|
|
lastClickTime: 0,
|
|
|
- videoRetryCounts: {}, // 记录每个直播间的视频重试次数,格式: { liveId: 次数 }
|
|
|
|
|
|
|
+ videoRetryCounts: Object.create(null), // 记录每个直播间的视频重试次数,格式: { liveId: 次数 }
|
|
|
|
|
|
|
|
clickDelay: 300, // 300ms内只响应一次点击
|
|
clickDelay: 300, // 300ms内只响应一次点击
|
|
|
liveUserTotal: 0,
|
|
liveUserTotal: 0,
|
|
@@ -650,27 +651,13 @@
|
|
|
liveId: null,
|
|
liveId: null,
|
|
|
userinfo: '', //用户信息
|
|
userinfo: '', //用户信息
|
|
|
userData: {},
|
|
userData: {},
|
|
|
-
|
|
|
|
|
|
|
+ diffTotalTime: ''
|
|
|
};
|
|
};
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- onLoad(options) {
|
|
|
|
|
|
|
+ async onLoad(options) {
|
|
|
if (options.liveId) {
|
|
if (options.liveId) {
|
|
|
this.liveId = 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) {
|
|
if (options.scene) {
|
|
|
this.scene = options.scene;
|
|
this.scene = options.scene;
|
|
@@ -688,19 +675,35 @@
|
|
|
if (options.companyId && options.companyUserId) {
|
|
if (options.companyId && options.companyUserId) {
|
|
|
this.qrFrom = `&companyId=${options.companyId}&companyUserId=${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() {
|
|
onPullDownRefresh() {
|
|
|
this.getLiveMsg(this.liveId)
|
|
this.getLiveMsg(this.liveId)
|
|
@@ -720,7 +723,6 @@
|
|
|
await this.getUserInfo()
|
|
await this.getUserInfo()
|
|
|
}
|
|
}
|
|
|
this.uuId = generateRandomString(16)
|
|
this.uuId = generateRandomString(16)
|
|
|
- this.previousToken = await uni.getStorageSync('AppToken')
|
|
|
|
|
const isLiveLogin = uni.getStorageSync('isLiveLogin')
|
|
const isLiveLogin = uni.getStorageSync('isLiveLogin')
|
|
|
this.share = uni.getStorageSync('share')
|
|
this.share = uni.getStorageSync('share')
|
|
|
this.scene = uni.getStorageSync('scene')
|
|
this.scene = uni.getStorageSync('scene')
|
|
@@ -835,12 +837,12 @@
|
|
|
if (videoContext) {
|
|
if (videoContext) {
|
|
|
videoContext.pause();
|
|
videoContext.pause();
|
|
|
}
|
|
}
|
|
|
- // 清理大数据
|
|
|
|
|
- this.talklist = [];
|
|
|
|
|
- this.liveViewersData = [];
|
|
|
|
|
- this.liveViewers = [];
|
|
|
|
|
- this.products = [];
|
|
|
|
|
- this.liveItem=[];
|
|
|
|
|
|
|
+ // 清理大数据
|
|
|
|
|
+ this.talklist = [];
|
|
|
|
|
+ this.liveViewersData = [];
|
|
|
|
|
+ this.liveViewers = [];
|
|
|
|
|
+ this.products = [];
|
|
|
|
|
+ this.liveItem = [];
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
mounted() {
|
|
mounted() {
|
|
@@ -875,6 +877,152 @@
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
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() {
|
|
goMiniProgram() {
|
|
|
// uni.navigateToMiniProgram({
|
|
// uni.navigateToMiniProgram({
|
|
|
// appId: 'wx45cf09091aead547',
|
|
// appId: 'wx45cf09091aead547',
|
|
@@ -900,6 +1048,10 @@
|
|
|
|
|
|
|
|
// 清理所有定时器
|
|
// 清理所有定时器
|
|
|
clearAllTimers() {
|
|
clearAllTimers() {
|
|
|
|
|
+ if (this.scrollTimer) {
|
|
|
|
|
+ clearTimeout(this.scrollTimer);
|
|
|
|
|
+ this.scrollTimer = null;
|
|
|
|
|
+ }
|
|
|
if (this.liveViewDataTimer) {
|
|
if (this.liveViewDataTimer) {
|
|
|
clearInterval(this.liveViewDataTimer);
|
|
clearInterval(this.liveViewDataTimer);
|
|
|
this.liveViewDataTimer = null;
|
|
this.liveViewDataTimer = null;
|
|
@@ -1022,20 +1174,24 @@
|
|
|
internetTraffic(param)
|
|
internetTraffic(param)
|
|
|
},
|
|
},
|
|
|
scrollToBottom() {
|
|
scrollToBottom() {
|
|
|
- this.$nextTick(() => {
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
|
|
+ if (this.scrollTimer) {
|
|
|
|
|
+ clearTimeout(this.scrollTimer);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.scrollTimer = setTimeout(() => {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
const query = uni.createSelectorQuery().in(this);
|
|
const query = uni.createSelectorQuery().in(this);
|
|
|
- // 获取 scroll-view 和内容的高度
|
|
|
|
|
query.select('.scrolly').boundingClientRect(scrollRect => {
|
|
query.select('.scrolly').boundingClientRect(scrollRect => {
|
|
|
|
|
+ if (!scrollRect) return;
|
|
|
|
|
+
|
|
|
query.select('.scrolly').scrollOffset(scrollOffset => {
|
|
query.select('.scrolly').scrollOffset(scrollOffset => {
|
|
|
- // 计算新的滚动位置
|
|
|
|
|
const newScrollTop = scrollOffset.scrollHeight - scrollRect
|
|
const newScrollTop = scrollOffset.scrollHeight - scrollRect
|
|
|
.height;
|
|
.height;
|
|
|
this.scrollTop = newScrollTop;
|
|
this.scrollTop = newScrollTop;
|
|
|
}).exec();
|
|
}).exec();
|
|
|
}).exec();
|
|
}).exec();
|
|
|
- }, 100);
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ });
|
|
|
|
|
+ }, 0);
|
|
|
},
|
|
},
|
|
|
// 恢复页面活动
|
|
// 恢复页面活动
|
|
|
async resumePageActivity() {
|
|
async resumePageActivity() {
|
|
@@ -1353,8 +1509,8 @@
|
|
|
onVideoTimeUpdate(e) {
|
|
onVideoTimeUpdate(e) {
|
|
|
// 获取当前播放时间
|
|
// 获取当前播放时间
|
|
|
this.videoCurrentTime = e.detail.currentTime;
|
|
this.videoCurrentTime = e.detail.currentTime;
|
|
|
- // 每隔5秒保存一次进度(避免频繁存储)
|
|
|
|
|
- if (Math.floor(this.videoCurrentTime) % 5 === 0) {
|
|
|
|
|
|
|
+ // 每隔10秒保存一次进度(避免频繁存储)
|
|
|
|
|
+ if (Math.floor(this.videoCurrentTime) % 10 === 0) {
|
|
|
this.saveVideoProgress();
|
|
this.saveVideoProgress();
|
|
|
}
|
|
}
|
|
|
// this.setVideoProgress();
|
|
// this.setVideoProgress();
|
|
@@ -1450,15 +1606,13 @@
|
|
|
.catch(rej => {});
|
|
.catch(rej => {});
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// 我的中奖名单
|
|
// 我的中奖名单
|
|
|
getMyLottery() {
|
|
getMyLottery() {
|
|
|
this.winning = true
|
|
this.winning = true
|
|
|
myLottery().then(res => {
|
|
myLottery().then(res => {
|
|
|
if (res.code == 200) {
|
|
if (res.code == 200) {
|
|
|
- console.log("我的中奖名单", res)
|
|
|
|
|
|
|
+ // console.log("我的中奖名单", res)
|
|
|
this.prizeAll = res.data.list || {};
|
|
this.prizeAll = res.data.list || {};
|
|
|
-
|
|
|
|
|
} else {
|
|
} else {
|
|
|
|
|
|
|
|
}
|
|
}
|
|
@@ -1655,9 +1809,9 @@
|
|
|
const hours = this.padZero(Math.floor(totalSeconds / 3600));
|
|
const hours = this.padZero(Math.floor(totalSeconds / 3600));
|
|
|
const minutes = this.padZero(Math.floor((totalSeconds % 3600) / 60));
|
|
const minutes = this.padZero(Math.floor((totalSeconds % 3600) / 60));
|
|
|
const seconds = this.padZero(totalSeconds % 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, "diffMs", diffMs);
|
|
|
- this.$set(this.liveItem, "totalSeconds", totalSeconds);
|
|
|
|
|
|
|
+ // this.$set(this.liveItem, "totalSeconds", totalSeconds);
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
padZero(num) {
|
|
padZero(num) {
|
|
@@ -1795,7 +1949,7 @@
|
|
|
const query = uni.createSelectorQuery().in(this);
|
|
const query = uni.createSelectorQuery().in(this);
|
|
|
query.select('.view-box').boundingClientRect(data => {
|
|
query.select('.view-box').boundingClientRect(data => {
|
|
|
if (data) {
|
|
if (data) {
|
|
|
- this.scrollHeight = data.height - 80 ; // 80是标题高度,120是底部高度
|
|
|
|
|
|
|
+ this.scrollHeight = data.height - 80; // 80是标题高度,120是底部高度
|
|
|
}
|
|
}
|
|
|
}).exec();
|
|
}).exec();
|
|
|
});
|
|
});
|
|
@@ -2064,7 +2218,6 @@
|
|
|
//直播间点赞、关注、在线人数数据
|
|
//直播间点赞、关注、在线人数数据
|
|
|
getliveViewData(liveItem) {
|
|
getliveViewData(liveItem) {
|
|
|
if (!liveItem || !this.liveId) return;
|
|
if (!liveItem || !this.liveId) return;
|
|
|
-
|
|
|
|
|
getLiveViewData(this.liveId).then(res => {
|
|
getLiveViewData(this.liveId).then(res => {
|
|
|
if (res.code == 200) {
|
|
if (res.code == 200) {
|
|
|
// 强制响应式更新,确保数据实时显示
|
|
// 强制响应式更新,确保数据实时显示
|
|
@@ -2331,6 +2484,25 @@
|
|
|
seconds: formatNum(seconds)
|
|
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消息
|
|
// 处理Socket消息
|
|
|
async handleSocketMessage(message) {
|
|
async handleSocketMessage(message) {
|
|
|
let data = JSON.parse(message.data)
|
|
let data = JSON.parse(message.data)
|
|
@@ -2349,15 +2521,10 @@
|
|
|
title: '连接已断开,正在重试...',
|
|
title: '连接已断开,正在重试...',
|
|
|
icon: 'none'
|
|
icon: 'none'
|
|
|
});
|
|
});
|
|
|
- this.handleReconnect(); // 主动触发重连
|
|
|
|
|
|
|
+ this.handleReconnect();
|
|
|
return;
|
|
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') {
|
|
} else if (socketMessage.cmd == 'red') {
|
|
|
const redData = socketMessage.data ? JSON.parse(socketMessage.data) : {};
|
|
const redData = socketMessage.data ? JSON.parse(socketMessage.data) : {};
|
|
|
this.redInfo = redData || {};
|
|
this.redInfo = redData || {};
|
|
@@ -2482,11 +2649,7 @@
|
|
|
this.redTimer = null;
|
|
this.redTimer = null;
|
|
|
}
|
|
}
|
|
|
// 请求最新直播间数据
|
|
// 请求最新直播间数据
|
|
|
- await this.getliving(this.liveId); // 注意:需用 await 确保数据更新完成
|
|
|
|
|
-
|
|
|
|
|
- // 强制触发视图更新(兜底方案,若上述步骤仍不生效)
|
|
|
|
|
- // this.$forceUpdate();
|
|
|
|
|
-
|
|
|
|
|
|
|
+ await this.getliving(this.liveId);
|
|
|
} else if (socketMessage.cmd == 'Integral') {
|
|
} else if (socketMessage.cmd == 'Integral') {
|
|
|
this.integral = {
|
|
this.integral = {
|
|
|
msg: socketMessage.msg,
|
|
msg: socketMessage.msg,
|
|
@@ -2521,12 +2684,12 @@
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
sendMsg(retries = 1) {
|
|
sendMsg(retries = 1) {
|
|
|
- // 防止连续点击发送两次(短时锁定)
|
|
|
|
|
|
|
+ // 防止连续点击发送两次(800ms短时锁定)
|
|
|
if (this.isSending) return;
|
|
if (this.isSending) return;
|
|
|
this.isSending = true;
|
|
this.isSending = true;
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
this.isSending = false;
|
|
this.isSending = false;
|
|
|
- }, 800); // 800ms 内禁止再次发送
|
|
|
|
|
|
|
+ }, 800);
|
|
|
|
|
|
|
|
const text = (this.value || '').trim();
|
|
const text = (this.value || '').trim();
|
|
|
if (!text) {
|
|
if (!text) {
|
|
@@ -2602,7 +2765,6 @@
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
</script>
|
|
</script>
|
|
@@ -2730,13 +2892,17 @@
|
|
|
color: #181818;
|
|
color: #181818;
|
|
|
font-weight: 500;
|
|
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 {
|
|
.talk-list {
|
|
|
will-change: transform; // 提示浏览器优化
|
|
will-change: transform; // 提示浏览器优化
|
|
|
contain: layout style paint; // 限制渲染范围
|
|
contain: layout style paint; // 限制渲染范围
|
|
@@ -3367,8 +3533,13 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@keyframes simpleFade {
|
|
@keyframes simpleFade {
|
|
|
- from {opacity: 0;}
|
|
|
|
|
- to {opacity: 1;}
|
|
|
|
|
|
|
+ from {
|
|
|
|
|
+ opacity: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ to {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.shop-prompt {
|
|
.shop-prompt {
|