|
@@ -230,19 +230,20 @@
|
|
|
<view class="fs26">投诉</view>
|
|
<view class="fs26">投诉</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
-
|
|
|
|
|
<view class="chat-content-wrapper"
|
|
<view class="chat-content-wrapper"
|
|
|
- :style="{height:liveItem.status == 1 && !liveItem.previewUrl && liveItem.showType == 2?'700rpx':''}"
|
|
|
|
|
|
|
+ :style="{ 'height':liveItem.status == 1 && !liveItem.previewUrl && liveItem.showType == 2?'48vh':''}"
|
|
|
:class="{ 'chat-content-focused': isFocus }">
|
|
:class="{ 'chat-content-focused': isFocus }">
|
|
|
<view class="notice-message" v-if="isShowNotice"
|
|
<view class="notice-message" v-if="isShowNotice"
|
|
|
|
|
+ :style="{ 'display':isFocus&&liveItem.showType == 2?'none':''}"
|
|
|
:class="liveItem.showType == 1 ? 'horizontal-notice' : 'horizontal-notice2'">
|
|
:class="liveItem.showType == 1 ? 'horizontal-notice' : 'horizontal-notice2'">
|
|
|
公告消息: {{notice.msg}}
|
|
公告消息: {{notice.msg}}
|
|
|
</view>
|
|
</view>
|
|
|
<scroll-view id="msgScroll" v-if="Array.isArray(talklist)" enable-flex scroll-y="true"
|
|
<scroll-view id="msgScroll" v-if="Array.isArray(talklist)" enable-flex scroll-y="true"
|
|
|
- :style="{ height: liveItem.showType === 1?`calc(100% - ${commonViewHeight}px)`:liveItem.status == 1?'100%':'',marginTop:liveItem.showType === 1?commonViewHeight+'px':'' }"
|
|
|
|
|
|
|
+ :style="{ height: liveItem.showType === 1 || liveItem.showType == 2 && !isFocus?`calc(100% - ${commonViewHeight}px)`:'',
|
|
|
|
|
+ marginTop:liveItem.showType === 1?commonViewHeight+'px':liveItem.showType == 2 && !isFocus?`calc(${commonViewHeight}px + 20rpx)`:'' }"
|
|
|
:enhanced="true" :bounces="false" :show-scrollbar="false" :fast-deceleration="false"
|
|
:enhanced="true" :bounces="false" :show-scrollbar="false" :fast-deceleration="false"
|
|
|
:enable-back-to-top="false" class="message-scroll-view"
|
|
:enable-back-to-top="false" class="message-scroll-view"
|
|
|
- :class="liveItem.status == 1 ? '' : ''" :scroll-top="scrollTop"
|
|
|
|
|
|
|
+ :scroll-top="scrollTop"
|
|
|
:scroll-into-view="scrollIntoView" @scroll="onScroll" ref="scrollView">
|
|
:scroll-into-view="scrollIntoView" @scroll="onScroll" ref="scrollView">
|
|
|
<view class="message-list" v-for="(item, talkIndex) in (talklist || [])"
|
|
<view class="message-list" v-for="(item, talkIndex) in (talklist || [])"
|
|
|
:key="item.uniqueId " :id="`list_${item.uniqueId }`" v-show="item.cmd != 'red' ">
|
|
:key="item.uniqueId " :id="`list_${item.uniqueId }`" v-show="item.cmd != 'red' ">
|
|
@@ -817,13 +818,6 @@
|
|
|
errorCount: 0, // 错误计数
|
|
errorCount: 0, // 错误计数
|
|
|
lastPerformanceCheck: 0, // 上次性能检查时间
|
|
lastPerformanceCheck: 0, // 上次性能检查时间
|
|
|
|
|
|
|
|
- // 观看时长统计相关
|
|
|
|
|
- watchStartTime: 0, // 观看开始时间(毫秒时间戳)
|
|
|
|
|
- accumulatedWatchDuration: 0, // 累计观看时长(秒)
|
|
|
|
|
- isPageVisible: true, // 页面是否可见
|
|
|
|
|
- lastPauseTime: 0, // 上次暂停时间
|
|
|
|
|
- watchDurationTimer: null, // 观看时长计时器
|
|
|
|
|
-
|
|
|
|
|
stayTime: 0,
|
|
stayTime: 0,
|
|
|
startTime: 0,
|
|
startTime: 0,
|
|
|
|
|
|
|
@@ -1163,12 +1157,6 @@
|
|
|
// }
|
|
// }
|
|
|
// 恢复播放和连接
|
|
// 恢复播放和连接
|
|
|
await this.resumePageActivity();
|
|
await this.resumePageActivity();
|
|
|
-
|
|
|
|
|
- // 恢复观看时长统计(如果之前已经开始统计)
|
|
|
|
|
- if (this.watchStartTime > 0 || this.accumulatedWatchDuration > 0) {
|
|
|
|
|
- this.resumeWatchDurationTracking();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// this.userinfo = JSON.parse(uni.getStorageSync('userInfo'));
|
|
// this.userinfo = JSON.parse(uni.getStorageSync('userInfo'));
|
|
|
this.userinfo = uni.getStorageSync('userinfo');
|
|
this.userinfo = uni.getStorageSync('userinfo');
|
|
|
this.isAgreement = uni.getStorageSync('isAgreement');
|
|
this.isAgreement = uni.getStorageSync('isAgreement');
|
|
@@ -1352,10 +1340,6 @@
|
|
|
// 清除所有定时器(使用增强清理)
|
|
// 清除所有定时器(使用增强清理)
|
|
|
// this.clearAllTimersEnhanced();
|
|
// this.clearAllTimersEnhanced();
|
|
|
// this.stopHeartBeat();
|
|
// this.stopHeartBeat();
|
|
|
-
|
|
|
|
|
- // 暂停观看时长统计
|
|
|
|
|
- this.pauseWatchDurationTracking();
|
|
|
|
|
-
|
|
|
|
|
// 页面隐藏时,提交当前流量数据
|
|
// 页面隐藏时,提交当前流量数据
|
|
|
if (this.videoLoaded && this.trafficStartTime && this.trafficTimer) {
|
|
if (this.videoLoaded && this.trafficStartTime && this.trafficTimer) {
|
|
|
const watchDuration = Math.floor((Date.now() - this.trafficStartTime) / 1000);
|
|
const watchDuration = Math.floor((Date.now() - this.trafficStartTime) / 1000);
|
|
@@ -1379,10 +1363,6 @@
|
|
|
onUnload() {
|
|
onUnload() {
|
|
|
// 保存视频进度
|
|
// 保存视频进度
|
|
|
this.saveVideoProgress();
|
|
this.saveVideoProgress();
|
|
|
-
|
|
|
|
|
- // 停止观看时长统计
|
|
|
|
|
- this.stopWatchDurationTracking();
|
|
|
|
|
-
|
|
|
|
|
// 用户退出时,再次请求一次10s流量接口
|
|
// 用户退出时,再次请求一次10s流量接口
|
|
|
if (this.videoLoaded && this.trafficStartTime) {
|
|
if (this.videoLoaded && this.trafficStartTime) {
|
|
|
const watchDuration = Math.floor((Date.now() - this.trafficStartTime) / 1000);
|
|
const watchDuration = Math.floor((Date.now() - this.trafficStartTime) / 1000);
|
|
@@ -1508,124 +1488,6 @@
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
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() {
|
|
noticeHeightFun() {
|
|
|
const query = uni.createSelectorQuery().in(this);
|
|
const query = uni.createSelectorQuery().in(this);
|
|
|
query.select('.notice-message').boundingClientRect(rect => {
|
|
query.select('.notice-message').boundingClientRect(rect => {
|
|
@@ -3170,7 +3032,7 @@
|
|
|
);
|
|
);
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- //发送心跳(包含观看时长)
|
|
|
|
|
|
|
+ //发送心跳
|
|
|
sendHeartBeat() {
|
|
sendHeartBeat() {
|
|
|
if (!this.isSocketAvailable() || !this.isNetworkAvailable) {
|
|
if (!this.isSocketAvailable() || !this.isNetworkAvailable) {
|
|
|
console.warn('网络不可用或Socket连接异常,跳过心跳发送');
|
|
console.warn('网络不可用或Socket连接异常,跳过心跳发送');
|
|
@@ -3178,9 +3040,6 @@
|
|
|
}
|
|
}
|
|
|
this.lastHeartBeatTime = Date.now();
|
|
this.lastHeartBeatTime = Date.now();
|
|
|
|
|
|
|
|
- // 计算当前累计观看时长
|
|
|
|
|
- const currentWatchDuration = this.getCurrentWatchDuration();
|
|
|
|
|
-
|
|
|
|
|
try {
|
|
try {
|
|
|
const heartBeatMsg = JSON.stringify({
|
|
const heartBeatMsg = JSON.stringify({
|
|
|
cmd: 'heartbeat',
|
|
cmd: 'heartbeat',
|
|
@@ -3188,14 +3047,12 @@
|
|
|
userId: this.userInfo.userId || '',
|
|
userId: this.userInfo.userId || '',
|
|
|
liveId: this.liveId,
|
|
liveId: this.liveId,
|
|
|
timestamp: this.lastHeartBeatTime,
|
|
timestamp: this.lastHeartBeatTime,
|
|
|
- networkType: this.networkType,
|
|
|
|
|
- data: String(currentWatchDuration)
|
|
|
|
|
|
|
+ networkType: this.networkType
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
this.socket.send({
|
|
this.socket.send({
|
|
|
data: heartBeatMsg,
|
|
data: heartBeatMsg,
|
|
|
success: () => {
|
|
success: () => {
|
|
|
- console.log(`心跳发送成功: 观看时长=${currentWatchDuration}秒`);
|
|
|
|
|
this.heartBeatRetryCount = 0; // 成功后重置重试次数
|
|
this.heartBeatRetryCount = 0; // 成功后重置重试次数
|
|
|
this.adjustHeartBeatInterval(true); // 网络良好,可适当延长间隔
|
|
this.adjustHeartBeatInterval(true); // 网络良好,可适当延长间隔
|
|
|
this.startPingTimeout(); // 启动超时检测
|
|
this.startPingTimeout(); // 启动超时检测
|
|
@@ -4640,12 +4497,7 @@
|
|
|
} else {
|
|
} else {
|
|
|
console.log(`WebSocket重连成功(第${this.reconnectCount}次尝试)`);
|
|
console.log(`WebSocket重连成功(第${this.reconnectCount}次尝试)`);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 启动心跳
|
|
|
|
|
this.startHeartBeat();
|
|
this.startHeartBeat();
|
|
|
-
|
|
|
|
|
- // 启动观看时长统计
|
|
|
|
|
- this.startWatchDurationTracking();
|
|
|
|
|
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -4693,9 +4545,6 @@
|
|
|
this.isSocketOpen = false;
|
|
this.isSocketOpen = false;
|
|
|
this.isConnecting = false;
|
|
this.isConnecting = false;
|
|
|
this.stopHeartBeat(); // 清除心跳定时器
|
|
this.stopHeartBeat(); // 清除心跳定时器
|
|
|
-
|
|
|
|
|
- // 暂停观看时长统计
|
|
|
|
|
- this.pauseWatchDurationTracking();
|
|
|
|
|
|
|
|
|
|
// 根据关闭原因决定是否重连
|
|
// 根据关闭原因决定是否重连
|
|
|
if (!this.isManualClose) {
|
|
if (!this.isManualClose) {
|
|
@@ -5896,7 +5745,24 @@
|
|
|
// flex-direction: column;
|
|
// flex-direction: column;
|
|
|
// position: absolute;
|
|
// position: absolute;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+ &.chat-area-container5 {
|
|
|
|
|
+ height: calc(85% - 450rpx);
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ transform: none; // 移除之前的变换
|
|
|
|
|
+ will-change: auto;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ // max-height: 40%;
|
|
|
|
|
+ // flex: 1;
|
|
|
|
|
+ // min-height: 0; // 重要:允许收缩到0
|
|
|
|
|
+ // // position: relative;
|
|
|
|
|
+ // transform: none; // 移除之前的变换
|
|
|
|
|
+ // will-change: auto;
|
|
|
|
|
+ // display: flex;
|
|
|
|
|
+ // flex-direction: column;
|
|
|
|
|
+ // position: absolute;
|
|
|
|
|
+ }
|
|
|
&.chat-area-focused {
|
|
&.chat-area-focused {
|
|
|
transform: translateY(calc(-1 * var(--keyboard-height, 0rpx))) translateZ(0);
|
|
transform: translateY(calc(-1 * var(--keyboard-height, 0rpx))) translateZ(0);
|
|
|
z-index: 1000;
|
|
z-index: 1000;
|
|
@@ -5953,7 +5819,10 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
&.horizontal-notice2 {
|
|
&.horizontal-notice2 {
|
|
|
- color: #fff !important
|
|
|
|
|
|
|
+ color: #fff !important;
|
|
|
|
|
+ top: 12rpx;
|
|
|
|
|
+ height: fit-content;
|
|
|
|
|
+ z-index: 2;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|