9 次代碼提交 8988846217 ... 6aaa7dcd2b

作者 SHA1 備註 提交日期
  qxj 6aaa7dcd2b add 1 周之前
  qxj 3ef257a9f9 add 1 周之前
  qxj 601660c513 Merge branch 'master' of http://1.14.104.71:10880/liujiaxin/zhibo 1 周之前
  qxj 609a3538d6 add 1 周之前
  qxj ff77374793 add 1 周之前
  qxj e4f2a905a0 add 1 周之前
  qxj 7efd92fb9f add 1 周之前
  qxj 58c17bbe66 add 1 周之前
  qxj 4abd2e07f1 add 1 周之前

+ 0 - 1
App.vue

@@ -13,7 +13,6 @@
 			if (options.query.companyId) {
 			if (options.query.companyId) {
 				uni.setStorageSync('share', options.query)
 				uni.setStorageSync('share', options.query)
 			}
 			}
-
 			if (options.query.scene) {
 			if (options.query.scene) {
 				uni.setStorageSync('scene', options.query.scene)
 				uni.setStorageSync('scene', options.query.scene)
 			}
 			}

+ 0 - 2
common/request.js

@@ -5,8 +5,6 @@ export default class Request {
 		let that = this;
 		let that = this;
 		let path = 'https://api.fhhx.runtzh.com';
 		let path = 'https://api.fhhx.runtzh.com';
 		// let path = 'http://x5d7cc68.natappfree.cc';//刘明欣
 		// let path = 'http://x5d7cc68.natappfree.cc';//刘明欣
-
-
 		// let path =  'http://192.168.10.122:7014';
 		// let path =  'http://192.168.10.122:7014';
 		// let path = 'http://192.168.10.126:7014';
 		// let path = 'http://192.168.10.126:7014';
 		// let path = 'https://live.test.ylrztop.com/live-api'; // 余红奇
 		// let path = 'https://live.test.ylrztop.com/live-api'; // 余红奇

+ 30 - 2
manifest.json

@@ -17,7 +17,10 @@
             "delay" : 0
             "delay" : 0
         },
         },
         /* 模块配置 */
         /* 模块配置 */
-        "modules" : {},
+        "modules" : {
+            "VideoPlayer" : {},
+            "LivePusher" : {}
+        },
         /* 应用发布信息 */
         /* 应用发布信息 */
         "distribute" : {
         "distribute" : {
             /* android打包配置 */
             /* android打包配置 */
@@ -41,7 +44,22 @@
                 ]
                 ]
             },
             },
             /* ios打包配置 */
             /* ios打包配置 */
-            "ios" : {},
+            "ios" : {
+                "capabilities" : {
+                    "entitlements" : {
+                        "com.apple.developer.networking.HotspotConfiguration" : true
+                    }
+                },
+                "urlschemewhitelist" : [
+                    "mqq",
+                    "mqqapi",
+                    "mqqwpa",
+                    "mqqbrowser",
+                    "mttbrowser",
+                    "weixin",
+                    "wechat"
+                ]
+            },
             /* SDK配置 */
             /* SDK配置 */
             "sdkConfigs" : {}
             "sdkConfigs" : {}
         }
         }
@@ -79,6 +97,7 @@
     "uniStatistics" : {
     "uniStatistics" : {
         "enable" : false
         "enable" : false
     },
     },
+	"sassImplementationName": "node-sass",
     "vueVersion" : "2",
     "vueVersion" : "2",
     "h5" : {
     "h5" : {
         "title" : "芳华惠选",
         "title" : "芳华惠选",
@@ -89,6 +108,15 @@
             "treeShaking" : {
             "treeShaking" : {
                 "enable" : true
                 "enable" : true
             }
             }
+        },
+        "router" : {
+            "mode" : "hash"
+        },
+        "async" : {
+            "loading" : "AsyncLoading",
+            "error" : "AsyncError",
+            "delay" : 200,
+            "timeout" : 60000
         }
         }
     }
     }
 }
 }

+ 7 - 1
pages.json

@@ -1037,7 +1037,13 @@
 						"navigationStyle": "custom",
 						"navigationStyle": "custom",
 						"softinputMode": "adjustResize", // 必须配置这个才能正常获取高度
 						"softinputMode": "adjustResize", // 必须配置这个才能正常获取高度
 						"app-plus": {
 						"app-plus": {
-							"bounce": "none"
+							"bounce": "none",
+							"videoFullscreen": true,
+							"videoAutoFullscreen": false,
+							"videoObjectFit": "contain"
+						},
+						"h5": {
+							"videoFullscreen": true
 						}
 						}
 					}
 					}
 				}
 				}

+ 0 - 280
pages/home/components/NewProduct.vue

@@ -1,280 +0,0 @@
-<template>
-    <view class="group-goods" v-if="detail.length>0">
-        <view class="title-box x-bc"  >
-            <text class="title">新品首发</text>
-            <view class="group-people x-f" @tap="navTo('/pages/home/productList')">
-                <text class="tip">更多</text>
-                <text class="cuIcon-right"></text>
-            </view>
-        </view>
-        <view class="goods-box swiper-box x-f">
-            <swiper class="carousel" circular @change="swiperChange" :autoplay="true" interval="10000" duration="2000">
-                <swiper-item v-for="(goods, index) in goodsList" :key="index" class="carousel-item">
-                    <view class="goods-list-box x-f">
-                        <block v-for="mgoods in goods" :key="mgoods.productId"  >
-                            <view class="min-goods" @tap="showProduct(mgoods)"  >
-                                <view class="img-box">
-                                    <view class="tag">new</view>
-                                    <image class="img" :src="mgoods.image" mode="widthFix"></image>
-                                </view>
-                                <view class="price-box">
-                                    <view class="y-f">
-                                        <text class="seckill-current">¥{{  mgoods.price  }}</text>
-                                        <text class="original">销量{{ mgoods.sales }}{{mgoods.unitName}}</text>
-                                    </view>
-                                </view>
-                                <view class="title">
-                                    <slot name="titleText"></slot>
-                                </view>
-                            </view>
-                        </block>
-                    </view>
-                </swiper-item>
-            </swiper>
-            <view class="swiper-dots" v-if="goodsList.length > 1">
-                <text :class="swiperCurrent === index ? 'dot-active' : 'dot'" v-for="(dot, index) in goodsList.length"
-                    :key="index"></text>
-            </view>
-        </view>
-    </view>
-</template>
-
-<script>
-    export default {
-        name: "NewProduct",
-         
-        data() {
-            return {
-                goodsList: [],
-                swiperCurrent: 0
-            };
-        },
-        props: {
-            detail: Array
-        },
-        computed: {},
-        created() {},
-        watch: {
-            detail(next) {
-                this.goodsList = this.sortData(next, 4);
-            }
-        },
-        methods: {
-            swiperChange(e) {
-                this.swiperCurrent = e.detail.current;
-            },
-            // 数据分层
-            sortData(oArr, length) {
-                let arr = [];
-                let minArr = [];
-                oArr.forEach(c => {
-                    if (minArr.length === length) {
-                        minArr = [];
-                    }
-                    if (minArr.length === 0) {
-                        arr.push(minArr);
-                    }
-                    minArr.push(c);
-                });
-
-                return arr;
-            },
-			navTo(url){
-				uni.navigateTo({
-					url: url
-				})
-			},
-			showProduct(item){
-				uni.navigateTo({
-					url: '/pages_shopping/shopping/productDetails?productId='+item.productId
-				})
-			},
-			
-            
-        }
-    }
-</script>
-
-
-<style lang="scss" scoped>
-    .group-goods {
-        position: relative;
-        z-index: 1;
-		background: #FFFFFF;
-		border-radius: 16upx;
-		margin-bottom: 20upx;
-		margin-top: 20upx;
-		padding: 20upx;
-    }
-
-    .swiper-box,
-    .carousel {
-        width: 700rpx;
-        height: 240upx;
-        position: relative;
-        border-radius: 20rpx;
-
-        .carousel-item {
-            width: 100%;
-            height: 100%;
-            // padding: 0 28upx;
-            overflow: hidden;
-        }
-
-        .swiper-image {
-            width: 100%;
-            height: 100%;
-            // border-radius: 10upx;
-            background: #ccc;
-        }
-    }
-
-    .swiper-dots {
-        display: flex;
-        position: absolute;
-        left: 50%;
-        transform: translateX(-50%);
-        bottom: 0rpx;
-        z-index: 66;
-
-        .dot {
-            width: 45rpx;
-            height: 3rpx;
-            background: #eee;
-            border-radius: 50%;
-            margin-right: 10rpx;
-        }
-
-        .dot-active {
-            width: 45rpx;
-            height: 3rpx;
-            background: #a8700d;
-            border-radius: 50%;
-            margin-right: 10rpx;
-        }
-    }
-
-    // 今日必拼+限时抢购
-    .group-goods {
-        background: #fff;
-        border-radius: 20rpx;
-        overflow: hidden;
-
-        .title-box {
-            padding-bottom: 20rpx;
-
-            .title {
-                font-size: 32rpx;
-                font-weight: bold;
-            }
-
-            .group-people {
-                .time-box {
-                    font-size: 26rpx;
-                    color: #edbf62;
-
-                    .count-text-box {
-                        width: 30rpx;
-                        height: 34rpx;
-                        background: #edbf62;
-                        text-align: center;
-                        line-height: 34rpx;
-                        font-size: 24rpx;
-                        border-radius: 6rpx;
-                        color: rgba(#fff, 0.9);
-                        margin: 0 8rpx;
-                    }
-                }
-
-                .head-box {
-                    .head-img {
-                        width: 40rpx;
-                        height: 40rpx;
-                        border-radius: 50%;
-                        background: #ccc;
-                    }
-                }
-
-                .tip {
-                    font-size: 24rpx;
-                    padding-left: 30rpx;
-                    color: #999999;
-                }
-
-                .cuIcon-right {
-                    font-size: 30rpx;
-                    line-height: 28rpx;
-                    color: #666;
-                }
-            }
-        }
-
-        .goods-box {
-            .goods-item {
-                margin-right: 22rpx;
-
-                &:nth-child(4n) {
-                    margin-right: 0;
-                }
-            }
-        }
-        .min-goods{
-            margin-right: 22rpx;
-
-        }
-    }
-	.min-goods {
-	  width: 152rpx;
-	  background: #fff;
-	  .img-box {
-	    width: 152rpx;
-	    height: 152rpx;
-	    overflow: hidden;
-	    position: relative;
-	
-	    .tag {
-	      position: absolute;
-	      left: 0;
-	      bottom: 0rpx;
-	      z-index: 2;
-	      line-height: 35rpx;
-	      background: linear-gradient(132deg, rgba(243, 223, 177, 1), rgba(243, 223, 177, 1), rgba(236, 190, 96, 1));
-	      border-radius: 0px 18rpx 18rpx 0px;
-	      padding: 0 10rpx;
-	      font-size: 24rpx;
-	      font-family: PingFang SC;
-	      font-weight: bold;
-	      color: rgba(120, 79, 6, 1);
-	    }
-	
-	    .img {
-	      width: 100%;
-	      background-color: #ccc;
-	    }
-	  }
-	
-	  .price-box {
-	    width: 100%;
-	    margin-top: 10rpx;
-	
-	    .seckill-current {
-	      font-size: 30rpx;
-	      font-weight: 500;
-	      color: rgba(225, 33, 43, 1);
-	    }
-	
-	    .original {
-	      font-size: 20rpx;
-	      font-weight: 400;
-	      // text-decoration: line-through;
-	      color: rgba(153, 153, 153, 1);
-	      margin-left: 14rpx;
-	    }
-	  }
-	
-	  .title {
-	    font-size: 26rpx;
-	  }
-	}
-	
-</style>

+ 2 - 2
pages/home/index.vue

@@ -404,11 +404,11 @@
 	import freeAudio from '@/components/chengpeng-audio/free-audio.vue'
 	import freeAudio from '@/components/chengpeng-audio/free-audio.vue'
 	import Menu from '@/components/Menu.vue'
 	import Menu from '@/components/Menu.vue'
 	import HotProduct from './components/HotProduct.vue'
 	import HotProduct from './components/HotProduct.vue'
-	import NewProduct from './components/NewProduct.vue'
+	// import NewProduct from './components/NewProduct.vue'
 	import TuiProduct from '@/components/tuiProduct.vue'
 	import TuiProduct from '@/components/tuiProduct.vue'
 	import {getUserInfo,bindPromoter} from '@/api/user'
 	import {getUserInfo,bindPromoter} from '@/api/user'
 	export default {
 	export default {
-		components: {zModal,freeAudio,Menu,HotProduct,NewProduct,TuiProduct},
+		components: {zModal,freeAudio,Menu,HotProduct,TuiProduct},
 		data() {
 		data() {
 			return { 
 			return { 
 				btnGroup: [{
 				btnGroup: [{

+ 3 - 11
pages_course/components/like.vue

@@ -195,14 +195,6 @@
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">
-	.like-container {
-		position: relative;
-	}
-
-	.image {
-		width: 48rpx;
-		height: 48rpx;
-	}
 
 
 	.like-icon {
 	.like-icon {
 		font-size: 28rpx;
 		font-size: 28rpx;
@@ -213,10 +205,10 @@
 	/* 动画容器 */
 	/* 动画容器 */
 	.like-container {
 	.like-container {
 		position: relative;
 		position: relative;
-
+		
 		.image {
 		.image {
-			width: 48rpx;
-			height: 48rpx;
+			width: 80rpx;
+			height: 80rpx;
 		}
 		}
 
 
 		/* 动画图标样式 */
 		/* 动画图标样式 */

文件差異過大導致無法顯示
+ 646 - 570
pages_course/living.vue


二進制
pages_course/living.vue.zip


+ 3688 - 0
pages_course/living1.vue

@@ -0,0 +1,3688 @@
+<template>
+	<view class="swiper-wrapper">
+		<view class="container">
+			<view class="content">
+				<view style="position: fixed;top: 0;z-index: 5;" class="content-top">
+					<view class="x-f">
+						<image v-if="!scene" @click="goBack" class="w60 h64 mr26" src="/static/images/return3.png" />
+						<view class="align-center"
+							style="padding: 6rpx 8rpx;height: 64rpx;background: rgba(0,0,0,0.5);border-radius: 32rpx;">
+							<u-avatar :src="liveItem.liveImgUrl||'/static/images/avatar.png'" :size="32"></u-avatar>
+							<view class="colorf ml10 mr6">
+								<view>{{liveItem.liveName?truncateString(liveItem.liveName,8):"未命名"}}</view>
+							</view>
+						</view>
+					</view>
+					<view v-if="Array.isArray(filteredViewers)" class=" align-center" @click="toggleViewerList"
+						style="margin-top: 120rpx;">
+						<view v-for="(item,viewerIndex) in filteredViewers" :key="viewerIndex">
+							<image v-if="item.avatar" class="w52 h52 mr4" style="border-radius: 26rpx;"
+								:src="item.avatar" />
+							<view v-else class="w52 h52 mr4"
+								:style="{backgroundColor: getUserRandomColor(item.userId), borderRadius:'50%'}">
+								<text class="text-white text-xs">{{getNicknameInitial(item.nickName)}}</text>
+							</view>
+						</view>
+						<view class="sum">{{liveUserTotal||0}}</view>
+					</view>
+				</view>
+				<!-- 右边的side -->
+				<view class="side-group">
+					<view class="side-item" @click="onLike">
+						<LikeButton :initialCount="100" :heartsPerClick="5" @like="onLike" />
+						<view>{{liveViewData && liveViewData.like||0}}</view>
+					</view>
+					<view class="side-item">
+						<button open-type="share" class="button button-reset">
+							<image class="image" src="/static/images/weixin.png" mode="widthFix" />
+						</button>
+						<view>分享</view>
+					</view>
+				</view>
+
+				<view class="activity-box">
+					<view class="item-box" @click="onRed()" v-if="isShowRed">
+						<view class="x-f">
+							<view class="tip">领红包</view>
+							<view class="item">
+								<image class="w70 img" src="/static/images/redbag.png" mode="widthFix" />
+							</view>
+						</view>
+					</view>
+					<view class="item-box" @click="onLottery()" v-if="isShowLottery&&countdown">
+						<view class="x-f">
+							<view class="tip">抽奖</view>
+							<view class="item">
+								<image class="w60" src="/static/images/lottery.png" mode="widthFix" />
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="shop-prompt f30 x-f"
+					v-if="showPurchasePrompt&&orderUser&&orderUser.count&&liveItem.status==2">
+					<image class="w32 h32 mr8" src="/static/images/shopping.png" />
+					<text>{{ orderUser.count || 0 }}人正在去购买</text>
+				</view>
+				<view class="videolist" v-if="liveItem.status==2">
+					<view class="video" :class="liveItem.showType == 1 ? 'video_row' : ''">
+						<!-- 直播 -->
+						<live-player v-if="liveItem.livingUrl && liveItem.liveType == 1" :id="'myLivePlayer_' + liveId"
+							:src="liveItem.livingUrl" autoplay mode="live" object-fit="contain" :muted="false"
+							orientation="vertical" :enable-play-gesture="false" min-cache="1" max-cache="3"
+							@statechange="onLiveStateChange($event, liveItem)" @error="onLiveError($event, liveItem)"
+							class="item"></live-player>
+						<!-- 录播 -->
+						<video v-if="liveItem.videoUrl&&liveItem.liveType==2" :id="`myVideo_${liveId}`" :autoplay="true"
+							class="item" :src="liveItem.videoUrl" :controls="false" object-fit="contain"
+							:custom-cache="false" :enable-progress-gesture="false" vslide-gesture-in-fullscreen="false"
+							: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">
+						</video>
+						<view v-if="liveItem.videoUrl&&liveItem.liveType==2" class="time">{{liveItem.totalTime}}
+						</view>
+					</view>
+				</view>
+				<view class="videolist" v-if="liveItem.status==3">
+					<view class="video" :class="liveItem.showType == 1 ? 'video_row' : ''">
+						<view class="end">直播已结束</view>
+					</view>
+				</view>
+				<view class="videolist" v-if="liveItem.status==4">
+					<view class="video" :class="liveItem.showType == 1 ? 'video_row' : ''">
+						<!-- 直播回放 -->
+						<video v-if="liveItem.videoUrl&&liveItem.liveType==3" :id="`myVideo_${liveId}`" class="item"
+							:src="liveItem.videoUrl" :autoplay="true" :controls="true" object-fit="contain"
+							:custom-cache="false" :enable-progress-gesture="liveItem.isSpeedAllowed"
+							vslide-gesture-in-fullscreen="true" :show-center-play-btn="true" :http-cache="false" loop
+							@error="videoError" @timeupdate="onVideoTimeUpdate" @loadedmetadata="onVideoMetaLoaded"
+							@pause="onVideoPause" @play="onVideoPlay" :enable-play-gesture="true" preload="auto"
+							@waiting="onVideoWaiting" type="application/x-mpegURL">
+						</video>
+						<view v-if="liveItem.videoUrl&&liveItem.liveType==3" class="lable">直播回放</view>
+					</view>
+				</view>
+				<view class="trailer-box" v-if="liveItem.status==1">
+					<video v-if="liveItem.previewUrl" :id="`myVideo_${liveId}`" class="item" :src="liveItem.previewUrl"
+						:autoplay="true" :loop="false" :controls="false" object-fit="contain" :custom-cache="false"
+						:enable-progress-gesture="false" vslide-gesture-in-fullscreen="false"
+						:show-center-play-btn="false" :http-cache="false" @error="videoError"
+						@loadedmetadata="onVideoMetaLoaded" @pause="onVideoPause" @play="onVideoPlay"
+						:disable-progress="true" :enable-play-gesture="true" @waiting="onVideoWaiting" preload="auto"
+						type="application/x-mpegURL">
+					</video>
+					<image v-if="liveItem.status==1&&!liveItem.previewUrl" class="img" src="/static/images/no_live.png">
+					</image>
+					<view class="countdown-item mt30 mb30" v-if="liveItem.status==1&&liveCountdown">
+						开播倒计时
+						<view class="x-f">
+							<view class="white">
+								{{liveCountdown.hours||"00"}}
+							</view>
+							<view class="white">
+								{{ liveCountdown.minutes||"00"}}
+							</view>
+							<view class="white">
+								{{ liveCountdown.seconds||"00" }}
+							</view>
+						</view>
+					</view>
+					<view class="name"> {{liveItem.liveName}}</view>
+					<view class="title" v-if="liveCountdown">暂未开播</view>
+					<view class="button" v-if="!isAgreement" @click="handleAgreement">预约直播</view>
+					<view class="button ash" v-if="isAgreement">已预约</view>
+					<view class="title" v-if="!liveCountdown">主播还在来的路上</view>
+				</view>
+				<view class="trailer-box" v-if="!liveItem">
+					<image class="img" src="/static/images/no_live.png">
+					</image>
+					<view class="title">暂无直播</view>
+				</view>
+
+				<!-- 底部聊天区域 -->
+				<view
+					:style="{position: 'fixed',width: '100%',bottom:isFocus ? keyboardHeight+'rpx' : '0'  ,zIndex:999}">
+					<view class="mt20" :style="{ height: isFocus ? '64rpx' : '30vh' }">
+						<scroll-view v-if="Array.isArray(talklist)" enable-flex scroll-y="true"
+							class="pl20 scrolly flex-1 column" style="width: calc(100% - 20rpx); height: 100%;"
+							:scroll-top="scrollTop" ref="scrollView">
+							<view class="list justify-start" v-for="(item,talkIndex) in (talklist||[])" :key="talkIndex"
+								:id="`list_${talkIndex}`" v-show="item.cmd!='red'&&item.cmd!='out'&&item.cmd!='entry'">
+								<view class="talk-list justify-start">
+									<view class="fs30" style="max-width: 100%;">
+										<text style="color: #FFDA73;">{{item.nickName||"未命名"}}:</text>
+										<text class='colorf'>{{item.msg}}</text>
+									</view>
+								</view>
+							</view>
+
+							<view v-if="showWelcomeMessage" class="welcome-message" style="max-width: 100%;">
+								<view class="list justify-start" v-show="inAndOut.cmd=='entry'||inAndOut.cmd=='out'">
+									<view class="talk-list justify-start">
+										<view class="fs30">
+											<text style="color: #ff89d6;">{{inAndOut.nickName||"未命名"}} </text>
+											<text class='colorf'>{{inAndOut.msg}}直播间</text>
+										</view>
+									</view>
+								</view>
+							</view>
+						</scroll-view>
+					</view>
+
+					<!-- 底部输入框和操作按钮 -->
+					<view class="justify-between p24">
+						<view class="x-f justify-between"
+							:style="{background:'#393939' ,padding: '10rpx 14rpx 10rpx 32rpx',boxSizing: 'border-box',borderRadius: '36rpx',width: isFocus ? '100%' : '580rpx'}">
+							<input :placeholder="placeholderText" v-model="value" placeholder-style="color:#e7e7e7;"
+								placeholder-class="placeholder-style" class="ml20 input-native" @focus="inputFocus"
+								@blur="inputBlur"
+								style="border: none; font-size: 32rpx; color: #ffffff; background: transparent; width: 70%;"
+								cursor-spacing="100" :adjust-position="false" />
+							<view class="send" @click="sendMsg()">发送</view>
+						</view>
+						<view class="justify-between mr15 align-center" v-if="!isFocus">
+							<view class="icon-bg ml20" @tap="openCart()">
+								<image src="/static/images/shopping.png" class="w58 h58" />
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="goods" v-if="isShowGoods">
+				<view class="top">
+					<view class="left">
+						<image class="w30 h30 mr8" src="/static/images/signal.png" />讲解中
+					</view>
+					<image @click="isShowGoods=false" class="w40 h40 " src="/static/images/del_black.png" />
+				</view>
+				<image class="photo" :src="goodsCard.imgUrl" />
+				<view class="item">
+					<view class="price"><text class="red">¥{{goodsCard.price}} </text><text
+							class="del">¥{{goodsCard.otPrice}}</text></view>
+					<view class="title oneline-hide">{{goodsCard.productName}}</view>
+					<view class="button" @click="goShop(goodsCard.productId,goodsCard.goodsId)">
+						立即抢购
+					</view>
+				</view>
+			</view>
+
+			<u-popup :show="isShowLotteryPop&&countdown" round='40rpx'>
+				<view class="prize-box" style="border-radius: 40rpx;height: fit-content;">
+					<image class="nav-img " src="/static/images/red_head.png" mode="widthFix" />
+					<image class="bg-img " src="/static/images/red_bg.png" />
+					<view class="prize-content">
+						<view class=" mr20" style="display: flex;justify-content: flex-end;">
+							<view
+								style="width: 80rpx;height: 80rpx;display: flex; justify-content: center;align-items: center;"
+								@click="isShowLotteryPop=false"><u-icon class="x-end" name="close" color="#fff"
+									size="20"></u-icon>
+							</view>
+						</view>
+						<view class="column align-center ">
+							<image class="w446 h80" src="/static/images/red_title.png" />
+							<view class="fs24 colorf x-f mt30 mb30">
+								开奖倒计时
+								<view class="x-f">
+									<view class="white-item">
+										{{countdown.hours||"00"}}
+									</view>
+									<view class="white-item">
+										{{ countdown.minutes||"00" }}
+									</view>
+									<view class="white-item">
+										{{ countdown.seconds||"00" }}
+									</view>
+								</view>
+							</view>
+							<view class="item-group">
+								<ThreeItemSwiper :products="lotteryProducts"></ThreeItemSwiper>
+							</view>
+							<view class="point-group" v-for="(item,index) in lotteryProducts" :key="index">
+							</view>
+							<view class="colorf fs28">
+								观看直播参与抽奖
+							</view>
+							<view class="button" @click="onClaim">参与抽奖</view>
+						</view>
+					</view>
+				</view>
+			</u-popup>
+			<u-popup :show="!!integral.status" round='20rpx' mode="center" bgColor='#ffffff' zIndex='10076'>
+				<view class="integral-box">
+					<view class="top">
+						<view class="title">观看视频领芳华币</view>
+						<image class="photo" src="/static/images/integral_bg.png" mode="widthFix" />
+					</view>
+					<view class="item">
+						<view class="title ">{{integral.msg}}</view>
+						<view class="button" @click="integral.status=false">确认</view>
+					</view>
+				</view>
+			</u-popup>
+
+			<u-popup :show="isShowRedCard" round='20rpx' mode="center" bgColor='transparent' zIndex='10076'>
+				<view class="red-card">
+					<image class="img" src="/static/images/red_card.png" />
+					<view class="red-content">
+						<view class="title">{{redCard.msg}}</view>
+						<view class="txt ">直播惊喜芳华币</view>
+						<view class="button" @click="isShowRedCard=false">确认</view>
+					</view>
+				</view>
+			</u-popup>
+
+			<!-- 中奖和未中奖 -->
+			<u-popup :show="isShowPrize&&havePrize" round='20rpx' mode="center" bgColor='#fff' zIndex='10076'>
+				<view class="prize-card" v-if="isCurrentUserWon">
+					<image class="nav-img " src="/static/images/red_head.png" mode="widthFix" />
+					<view class="title">恭喜您 中奖啦!</view>
+					<view class="prize-content" v-for="(item,index) in (prizeInfo||[])" :key="index">
+						<view class="item">{{item.userName}}</view>
+						<view class="item">{{item.userId}}</view>
+						<view class="txt item">{{item.prizeLevel}}等奖</view>
+					</view>
+					<view class="tip">请截图联系客服领取奖品</view>
+					<view class="button" @click="confirm">确认</view>
+				</view>
+				<view class="no-prize-card" v-else>
+					<image class="img" src="/static/images/no-prize.png" mode="widthFix" />
+					<view class="tip">很遗憾 您未中奖</view>
+					<view class="button" @click="confirm">确认</view>
+				</view>
+			</u-popup>
+
+
+			<!-- 中奖记录 -->
+			<!-- winning -->
+			<u-popup :show="winning" @close="closeWin" round='20rpx' bgColor='#f3f5f9' zIndex='10076'>
+				<view class="winning_record">
+					<image class="head_bg" src="/static/images/red_head.png" mode="widthFix"></image>
+					<image class="bg" src="/static/images/red_bg.png"></image>
+					<view class="winning_content">
+						<view class="title">我的中奖记录</view>
+						<view class="row mb40">
+							<view class="head">时间</view>
+							<view class="head">奖品</view>
+						</view>
+						<scroll-view enable-flex scroll-y v-if="prizeAll" style="height: 500rpx;">
+							<view class="row fs30 mb20" v-for="(item,index) in prizeAll" :key="index">
+								<view class="start">{{item.createTime}}</view>
+								<view class="end">{{item.productName?truncateString(item.productName,8):'' }}</view>
+							</view>
+						</scroll-view>
+						<view v-else class="f36 mt150" style="text-align: center;">
+							暂无中奖信息
+						</view>
+					</view>
+				</view>
+			</u-popup>
+			<!-- 观众列表弹窗 -->
+			<u-popup :show="showadd" @close="close" @open="openViews" round='20rpx' bgColor='#ffffff' zIndex='10077'>
+				<view class="view-box">
+					<view class="fs32" style="text-align: center;">在线观众</view>
+					<scroll-view v-if="Array.isArray(liveViewers)" scroll-y class="scroll-content"
+						:style="{height: scrollHeight + 'px'}" @scrolltolower="handleScrollToLower">
+						<view class="fs28 x-f mb20 mt20" v-for="(item,index) in (liveViewers||[])" :key="index">
+							<view
+								:style="{color: index === 0 ? '#FF3B30' : index === 1 ? '#FF9500' : index === 2 ? '#FFCC00' :  '#8E8E93',fontWeight: index < 3 ? 'bold' : 'normal',width: '50rpx'}"
+								class="mr10">{{index+1}}</view>
+							<u-avatar v-if="item.avatar" :src="item.avatar" :size="36"></u-avatar>
+							<view v-else class="w72 h72"
+								:style="{backgroundColor: getUserRandomColor(item.userId), borderRadius:'50%'}">
+								<text class="text-white text-sm">{{getNicknameInitial(item.nickName)}}</text>
+							</view>
+							<text class="ml16 f30">{{item.nickName||"未命名"}}</text>
+						</view>
+					</scroll-view>
+				</view>
+			</u-popup>
+
+			<!-- 更多弹窗 -->
+			<u-popup :show="isMore" @close="closeMore" round='20rpx' bgColor='#f3f5f9' zIndex='10076'>
+				<view class="more-block">
+					<view class="item" @click="navgetTo('/pages_shopping/live/integral'),isMore=false">
+						<image class="w48 h48" src="/static/images/order.png" />
+						<view style="text-align: center;">芳华币</view>
+					</view>
+					<view class=" item"
+						@click="navgetTo('/pages_shopping/live/storeOrderRefundList?liveId='+liveId),isMore=false">
+						<image class="w48 h48" src="/static/images/after_sales.png" />
+						<view style="text-align: center;">售后订单</view>
+					</view>
+					<view class=" item" @click="goMiniProgram(),isMore=false">
+						<image class="w48 h48" src="/static/images/points.png" />
+						<view style="text-align: center;">兑换好礼</view>
+					</view>
+					<view class="item" @click="getMyLottery(),isMore=false,winning=true">
+						<image class="w48 h48" src="/static/images/health_sel.png" />
+						<view style="text-align: center;">中奖记录</view>
+					</view>
+				</view>
+			</u-popup>
+
+			<!-- 商品弹窗 -->
+			<!-- show="true" -->
+			<u-popup :show="shopping" @close="closeShop" round='20rpx' bgColor='#f3f5f9' zIndex='10075'>
+				<view class="shoppop">
+					<view class="shoppop-top">
+						<view class="search-input x-f">
+							<image class="w24 mr16" src="/static/images/search.png" mode="widthFix" />
+							<input placeholder="请搜索商品" v-model="inputInfo" @input="handleSearchInput" />
+						</view>
+						<view class=" search-top" @click="navgetTo('/pages_shopping/live/order')">
+							<image class="w48 h48" src="/static/images/carts.png" />
+							<view style="text-align: center;">订单</view>
+						</view>
+						<view class="search-top" @click="isMore=true,shopping=false">
+							<image class="w48 h48" src="/static/images/search2.png" />
+							<view style="text-align: center;">更多</view>
+						</view>
+					</view>
+
+					<!-- <scroll-view enable-flex scroll-y class="shop-list" :style="{ height: boxHeight + 'px' }">
+						<view class="list-item" v-for="(item,index) in products" :key="index">
+							<view class="goods-img">
+								<image class="img" :src="item.imgUrl" mode="widthFix" />
+								<view class="goods-label">{{index+1}}</view>
+							</view>
+							<view class="goods-right">
+								<view class="goods-title">{{item.productName}}</view>
+								<view class="goods-people">{{item.sales}} 人已购</view>
+								<view class="goods-shop">
+									<text class="nummber"><text style="font-size: 20rpx;font-weight: 600;">¥</text><text
+											style="font-size: 36rpx;font-weight: bold;">{{Math.trunc(item.price)}}</text>.{{getPureDecimal(item.price)?getPureDecimal(item.price):'00'}}</text>
+									<view class="btn-group x-f">
+										<view class="collect-btn">
+											<image v-if="item.isFavorite" @click="onGoodsCollect(item)" class="w36 h36"
+												style="vertical-align: middle;"
+												src="/static/images/collect_select.png" />
+											<image v-else @click="onGoodsCollect(item)" class="w36 h36"
+												style="vertical-align: middle;" src="/static/images/collect.png" />
+										</view>
+										<view v-if="item.status==1" class="shop-btn"
+											@click="goShop(item.productId,item.goodsId)">去购买 </view>
+										<view v-else-if="item.status==0" class="shop-btn">
+											已下架</view>
+									</view>
+								</view>
+							</view>
+						</view>
+					</scroll-view> -->
+					<scroll-view enable-flex scroll-y class="shop-list" :style="{ height: boxHeight + 'px' }">
+						<!-- 骨架屏 -->
+						<view v-if="loadingProducts && products.length === 0" class="skeleton-list">
+							<view v-for="n in 6" :key="n" class="skeleton-item">
+								<view class="skeleton-img"></view>
+								<view class="skeleton-content">
+									<view class="skeleton-line short"></view>
+									<view class="skeleton-line medium"></view>
+									<view class="skeleton-line long"></view>
+								</view>
+							</view>
+						</view>
+						<!-- 实际商品列表 -->
+						<template v-else>
+							<view v-for="(item,index) in products" :key="index" class="list-item">
+								<view class="goods-img">
+									<image class="img" :src="item.imgUrl" mode="widthFix" />
+									<view class="goods-label">{{index+1}}</view>
+								</view>
+								<view class="goods-right">
+									<view class="goods-title">{{item.productName}}</view>
+									<view class="goods-people">{{item.sales}} 人已购</view>
+									<view class="goods-shop">
+										<text class="nummber"><text
+												style="font-size: 20rpx;font-weight: 600;">¥</text><text
+												style="font-size: 36rpx;font-weight: bold;">{{Math.trunc(item.price)}}</text>.{{getPureDecimal(item.price)?getPureDecimal(item.price):'00'}}</text>
+										<view class="btn-group x-f">
+											<view class="collect-btn">
+												<image v-if="item.isFavorite" @click="onGoodsCollect(item)"
+													class="w36 h36" style="vertical-align: middle;"
+													src="/static/images/collect_select.png" />
+												<image v-else @click="onGoodsCollect(item)" class="w36 h36"
+													style="vertical-align: middle;" src="/static/images/collect.png" />
+											</view>
+											<view v-if="item.status==1" class="shop-btn"
+												@click="goShop(item.productId,item.goodsId)">去购买 </view>
+											<view v-else-if="item.status==0" class="shop-btn">
+												已下架</view>
+										</view>
+									</view>
+								</view>
+							</view>
+						</template>
+					</scroll-view>
+				</view>
+			</u-popup>
+
+			<!-- 优惠券弹窗 -->
+			<view class="coupon-pop" v-if="isShowCoupon">
+				<view class="coupon-block">
+					<image class="bg" src="/static/images/coupon_bg.png" />
+					<image class="nav" src="/static/images/coupon_top.png" />
+					<image @click="isShowCoupon=false" class="w40 h40 close" style="z-index: 99;"
+						src="/static/images/close1.png" />
+					<view class="item">
+						<view class="title">{{couponInfo.couponName}}</view>
+						<view class="price">¥<text class="bold">{{couponInfo.couponPrice}}</text></view>
+						<view class="txt">满{{couponInfo.useMinPrice}}元可用</view>
+						<view class="txt" style="margin-top: 26rpx;">指定商品可用</view>
+						<view class="txt">自领取起{{couponInfo.couponTime}}天内有效</view>
+						<view class="button" @click="onCoupon()">
+							立即领券
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+	import LikeButton from '@/pages_course/components/like.vue'
+	import ThreeItemSwiper from '@/pages_course/components/ThreeItemSwiper.vue'
+	import CryptoJS from 'crypto-js'
+	import {
+		myLottery, // 我的中奖明细
+		coupon, //领取优惠券
+		liveLottery, // 抽奖查询
+		claim, //抽奖
+		liveRed, // 点击领红包
+		liveDataLike, // 点赞
+		collectStore, // 店铺收藏/取消收藏
+		collectGoods, // 商品收藏/取消收藏
+		watchUserList, //获取直播间用户(展示在线用户)
+		liveMsg, //获取最近聊天记录
+		// 小黄车
+		liveStore, //店铺展示,
+		liveOrderUser, //正在购买
+		getLiveInfo, //获取直播间信息接口
+		getLiveViewData, //直播间点赞、关注、在线人数数据
+		currentActivities, //红包 卡片 抽奖
+		getlive,
+		subNotifyLive,
+		internetTraffic, // 流量(缓冲百分比),
+		liveInternetTraffic // 直播流量(缓冲百分比),
+	} from '@/api/living.js'
+	import {
+		getUserInfo
+	} from '@/api/user'
+	import {
+		generateRandomString
+	} from "@/utils/common.js"
+	import dayjs from 'dayjs';
+	import {
+		nextTick
+	} from "vue"
+
+	var isSocketOpen = false;
+	var socket = null;
+
+	export default {
+		components: {
+			ThreeItemSwiper,
+			LikeButton
+		},
+		data() {
+			return {
+				uuId: "",
+				totalTraffic: 0, // 总流量(字节)
+				bitrate: 800, // 录播默认码率 0.16Mbps
+				bitrateLive: 1600, // 直播默认码率 0.16Mbps
+
+				//定时器
+				trafficTimer: null,
+				pingTimeoutTimer: null, // 心跳超时定时器
+				heartBeatTimer: null, // 心跳定时器
+				liveViewDataTimer: null,
+				reconnectTimer: null, // 重连定时器
+				scrollTimer: null, // 滚动防抖定时器
+				searchTimer: null, //搜索
+				purchasePromptTimer: null, //购买提示
+				welcomeTimer: null, //进入离开直播间定时器
+				redTimer: null,
+				liveStartTimer: null,
+				lotteryTimer: null,
+
+
+				stayTime: 0,
+				startTime: 0,
+
+				scrollTop: 0,
+				isOnload: false,
+				isConnecting: false, // 是否正在连接中
+				previousToken: null,
+				hasInitialized: false,
+
+				liveViewersData: [],
+				liveUserCalled: false, //调用过watchUserList没
+				userRandomColors: {}, // 缓存用户ID -> 随机色的映射
+
+				heartBeatRetryCount: 0, // 心跳发送重试次数(避免一次失败就重连)
+				maxHeartBeatRetries: 2, // 心跳最大重试次数
+				pingTimeout: 20000, // 心跳超时时间从10s延长到20s(应对网络波动)
+				shownEntryUsers: new Set(), // 存储已显示过「进入提示」的用户ID
+
+				socket: null, // WebSocket 实例
+				isSocketOpen: false, // 连接是否已打开
+				heartBeatInterval: 15000, // 心跳发送间隔(15秒)
+				reconnectCount: 0, // 当前重连次数
+				maxReconnectAttempts: 3, // 最大重连次数
+				isManualClose: false, // 是否手动关闭(用于区分主动关闭和异常断开)
+
+				templateId: 'fxYJu817lxHNKXl0hJypb-y-lLm8CNmGbcwpQmasCVg',
+				isAgreement: false,
+
+
+
+				wsNewUrl: 'wss://api.fhhx.runtzh.com/ws/app/webSocket',
+				// wsNewUrl: 'ws://192.168.10.166:7114/ws/app/webSocket',
+				qrFrom: null,
+				scene: '',
+
+				liveCountdown: {}, //直播倒计时
+				countdown: {}, //抽奖倒计时
+				liveViewData: {},
+
+				keyboardHeight: 0,
+				videoCurrentTime: 0, // 当前视频播放时间
+				videoProgressKey: '', // 存储进度的key
+				inAndOut: {},
+				winning: false,
+				isShowPrize: false,
+				isShowCoupon: false,
+				prizeInfo: [],
+				havePrize: uni.getStorageSync('havePrize') || false, //是否参与抽奖
+				countDownKey: 0,
+				lotteryProducts: [],
+				lotteryList: [],
+				talklist: [],
+				isShowLotteryPop: false,
+				liveItem: {},
+				isSending: false,
+				isMore: false,
+
+				value: '',
+				placeholderText: '说点什么...',
+
+				prizeAll: [],
+				isShowLottery: false,
+				isShowRedCard: false,
+				redCard: null, //点击红包出现弹窗
+				integral: {},
+				lotteryInfo: {},
+				goodsCard: {},
+				couponInfo: {},
+				redInfo: {},
+				storeId: null,
+				isFocus: false,
+				shopping: false,
+
+				inputInfo: '',
+				showWelcomeMessage: false,
+				scrollIntoView: '',
+				isShowGoods: false,
+				isShowRed: false,
+				lastClickTime: 0,
+				videoRetryCounts: {}, // 记录每个直播间的视频重试次数,格式: { liveId: 次数 }
+
+				clickDelay: 300, // 300ms内只响应一次点击
+				liveUserTotal: 0,
+				viewPageSize: 10, // 每页数量
+				viewPageNum: 1, // 当前页码
+				viewLoading: false, // 是否正在加载
+				scrollHeight: 0,
+
+				showPurchasePrompt: false,
+				prevOrderCount: 0, // 用于记录上一次的购买人数
+				videoUrl: null,
+				showType: 1, //横屏1 竖屏2
+				boxHeight: 300, //小黄车高度
+				liveViewers: [], //观众
+				livingUrl: "",
+				products: [],
+				loadingProducts: false, // 商品加载状态
+				orderUser: {}, //正在购买
+				userType: 0,
+				timestamp: '',
+				showadd: false,
+				liveId: null,
+				userinfo: '', //用户信息
+				userData: {},
+
+			};
+		},
+
+
+		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;
+				const decodedScene = decodeURIComponent(this.scene);
+				const params = {};
+				decodedScene.split('&').forEach(item => {
+					const [key, value] = item.split('=');
+					params[key] = value;
+					this.liveId = params.a;
+				})
+				if (params.b && params.c) {
+					this.qrFrom = `&companyId=${params.b}&companyUserId=${params.c}`;
+				}
+			}
+			if (options.companyId && options.companyUserId) {
+				this.qrFrom = `&companyId=${options.companyId}&companyUserId=${options.companyUserId}`;
+			}
+
+			// 初始化直播间列表
+			this.$nextTick(() => {
+				if (this.liveId) {
+					this.getliving(this.liveId);
+					this.isOnload = true
+					this.getLiveMsg(this.liveItem);
+					this.getliveViewData(this.liveItem);
+
+				} else {
+					console.error("直播间 ID(liveId)未获取到");
+				}
+			})
+		},
+		onPullDownRefresh() {
+			this.getLiveMsg(this.liveId)
+			this.getliveUser()
+			setTimeout(() => {
+				uni.stopPullDownRefresh()
+			}, 1000)
+		},
+		async onShow() {
+			if (this.liveId) {
+				await this.getLiveMsg(this.liveItem);
+			}
+			if (!this.liveViewData) {
+				this.getliveViewData(this.liveItem);
+			}
+			if (!this.userData) {
+				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')
+			if (this.share && this.share.length > 0) {
+				this.liveId = this.share.liveId
+				this.qrFrom = `&companyId=${this.share.companyId}&companyUserId=${this.share.companyUserId}`;
+				uni.removeStorageSync('share')
+			}
+			if (this.scene) {
+				const decodedScene = decodeURIComponent(this.scene);
+				const params = {};
+				decodedScene.split('&').forEach(item => {
+					const [key, value] = item.split('=');
+					params[key] = value;
+					this.liveId = params.a;
+				})
+				if (params.b && params.c) {
+					this.qrFrom = `&companyId=${params.b}&companyUserId=${params.c}`;
+				}
+				uni.removeStorageSync('scene')
+			}
+			if (isLiveLogin) {
+				if (this.liveId) {
+					await this.getliving(this.liveId)
+					this.getCurrentActivities()
+					this.getliveOrder()
+					this.initSocket()
+				}
+				this.hasInitialized = true
+				uni.removeStorageSync('isLiveLogin');
+			}
+			// 恢复播放和连接
+			await this.resumePageActivity()
+			this.userinfo = JSON.parse(uni.getStorageSync("userInfo"))
+			this.isAgreement = uni.getStorageSync('isAgreement')
+
+			this.$nextTick(() => {
+				this.setVideoProgress();
+			});
+			if (this.lookTimer) {
+				clearInterval(this.lookTimer)
+				this.lookTimer = null;
+				this.stayTime = 0;
+				this.startTime = 0;
+			}
+			if (this.trafficTimer) {
+				clearInterval(this.trafficTimer)
+				this.trafficTimer = null;
+				this.startTime = 0;
+				this.totalTraffic = 0;
+			}
+			this.startTimer()
+		},
+
+		//分享给好友
+		onShareAppMessage() {
+			return {
+				title: '邀请你来观看直播:' + this.liveItem.liveName,
+				path: '/pages_course/living?companyId=-2&companyUserId=' + this.userData.userId + '&liveId=' + this.liveId,
+				imageUrl: '/static/images/logo.png',
+				success(res) {
+					console.log("分享成功", res);
+				},
+				fail(err) {
+					console.error("分享失败", err);
+				}
+			};
+		},
+		computed: {
+			filteredViewers() {
+				const safeLiveViewers = Array.isArray(this.liveViewersData) ? this.liveViewersData : [];
+				// 截取前3项
+				return safeLiveViewers.slice(0, 3);
+			},
+			isCurrentUserWon() {
+				if (!Array.isArray(this.prizeInfo) || !this.userData?.userId) {
+					return false;
+				}
+				return this.prizeInfo.some(item => {
+					return String(item.userId) === String(this.userData.userId);
+				});
+			}
+		},
+		onHide() {
+			//  清除所有定时器
+			this.clearAllTimers();
+			this.stopHeartBeat()
+		},
+
+		onUnload() {
+			this.stopHeartBeat()
+			this.saveVideoProgress()
+
+			if (this.liveItem) {
+				this.pauseVideo()
+				// 清除直播间的时间定时器
+				if (this.liveItem.timeTimer) {
+					clearInterval(this.liveItem.timeTimer);
+					this.liveItem.timeTimer = null; // 清空定时器标识
+				}
+			}
+			this.liveUserCalled = false
+			this.loadUserColorsFromStorage();
+			//  先关闭WebSocket
+			this.closeWebSocket(true);
+
+			//  清除所有定时器
+			this.clearAllTimers();
+			//  暂停视频
+			const videoId = `myVideo_${this.liveId}`;
+			const videoContext = uni.createVideoContext(videoId, this);
+			if (videoContext) {
+				videoContext.pause();
+			}
+			 // 清理大数据
+			  this.talklist = [];
+			  this.liveViewersData = [];
+			  this.liveViewers = [];
+			  this.products = [];
+			  this.liveItem=[];
+		},
+
+		mounted() {
+			this.getCurrentActivities();
+			this.getliveOrder()
+		},
+		watch: {
+			// 监听liveItem.status的变化
+			'liveItem.status': {
+				handler(newStatus, oldStatus) {
+					if (newStatus === undefined || oldStatus === undefined) return;
+					if (newStatus === oldStatus) return;
+					if (!this.liveId) {
+						console.warn("liveId不存在,无法触发getliving请求");
+						return;
+					}
+					// 状态变化时,调用getliving更新直播间数据
+					// console.log(`liveItem.status从${oldStatus}变为${newStatus},触发getliving请求`);
+					this.getliving(this.liveId);
+				},
+				deep: true,
+			},
+			// 监听orderUser.count的变化
+			'orderUser.count': {
+				handler(newVal, oldVal) {
+					if (newVal !== this.prevOrderCount) {
+						this.prevOrderCount = newVal;
+						this.showPurchaseMessage();
+					}
+				},
+				immediate: true
+			}
+		},
+		methods: {
+			goMiniProgram() {
+				// uni.navigateToMiniProgram({
+				// 	appId: 'wx45cf09091aead547',
+				// 	path: '/pages/home/index',
+				// 	success: function(res) {
+				// 		console.log('跳转成功', res);
+				// 	},
+				// 	fail: function(err) {
+				// 		console.error('跳转失败', err);
+				// 	}
+				// });
+				uni.showToast({
+					title: '系统升级中,兑换请联系伴学助手!',
+					icon: 'none'
+				});
+			},
+			// 阻止双击事件
+			preventDoubleClick(e) {
+				e.preventDefault();
+				e.stopPropagation();
+				return false;
+			},
+
+			// 清理所有定时器
+			clearAllTimers() {
+				if (this.liveViewDataTimer) {
+					clearInterval(this.liveViewDataTimer);
+					this.liveViewDataTimer = null;
+				}
+				if (this.redTimer) {
+					clearInterval(this.redTimer);
+					this.redTimer = null;
+				}
+				if (this.liveStartTimer) {
+					clearInterval(this.liveStartTimer);
+					this.liveStartTimer = null;
+				}
+				if (this.lotteryTimer) {
+					clearInterval(this.lotteryTimer);
+					this.lotteryTimer = null;
+				}
+				if (this.welcomeTimer) {
+					clearInterval(this.welcomeTimer);
+					this.welcomeTimer = null;
+				}
+				if (this.trafficInterval != null) {
+					clearInterval(this.trafficInterval)
+				}
+				if (this.lookTimer) {
+					clearInterval(this.lookTimer)
+					this.lookTimer = null;
+					this.stayTime = 0;
+					this.startTime = 0;
+				}
+				if (this.trafficTimer) {
+					clearInterval(this.trafficTimer)
+					this.trafficTimer = null;
+					this.startTime = 0;
+					this.totalTraffic = 0;
+				}
+				if (this.intervalId) {
+					clearInterval(this.intervalId);
+					this.intervalId = null;
+				}
+				if (this.reconnectTimer) {
+					clearInterval(this.reconnectTimer);
+					this.reconnectTimer = null;
+				}
+				if (this.scrollTimer) {
+					clearTimeout(this.scrollTimer);
+					this.scrollTimer = null;
+				}
+				if (this.searchTimer) {
+					clearTimeout(this.searchTimer);
+					this.searchTimer = null;
+				}
+				if (this.purchasePromptTimer) {
+					clearTimeout(this.purchasePromptTimer);
+					this.purchasePromptTimer = null;
+				}
+			},
+			//直播计算流量
+			startTrafficCalculation(bitrate) {
+				if (this.trafficTimer) {
+					clearInterval(this.trafficTimer);
+					this.trafficTimer = null;
+				}
+				this.startTime = Date.now();
+				var that = this
+				this.trafficTimer = setInterval(() => {
+					that.calculateTraffic(bitrate);
+				}, 10000); // 每10秒计算一次
+			},
+			// 计算流量
+			calculateTraffic(bitrate) {
+				const currentTime = Date.now();
+				const duration = (currentTime - this.startTime) / 1000; // 持续时间(秒)
+				// 流量 = 码率 × 时间
+				// 码率单位: bps, 时间单位: 秒, 流量单位: 比特
+				const trafficBits = bitrate * duration;
+				// 转换为字节
+				this.totalTraffic = trafficBits / 8;
+				this.getLiveInternetTraffic()
+			},
+
+			startTimer() {
+				this.startTime = Date.now()
+				this.lookTimer = setInterval(() => {
+					this.stayTime = Math.floor((Date.now() - this.startTime) / 1000)
+				}, 1000)
+			},
+
+			//直播、录播缓冲
+			getLiveInternetTraffic() {
+				if (!this.liveId) return;
+				const currentTime = this.stayTime / this.liveItem.duration * 100;
+				const param = {
+					userId: this.userData.userId || '',
+					liveId: this.liveId || '',
+					uuId: dayjs().format('YYYYMMDD') + this.uuId,
+					internetTraffic: this.totalTraffic,
+				}
+				liveInternetTraffic(param)
+			},
+			// 回放、预告缓冲
+			getInternetTraffic() {
+				if (!this.liveId || !this.liveId || !this.userData.userId || !this.uuId) return;
+				const currentTime = this.stayTime / this.liveItem.duration * 100;
+				const param = {
+					videoType: this.liveItem.videoType,
+					videoId: this.liveItem.videoId,
+					userId: this.userData.userId,
+					liveId: this.liveId,
+					uuId: dayjs().format('YYYYMMDD') + this.uuId,
+					duration: this.liveItem.duration,
+					bufferRate: currentTime,
+				}
+				if (this.liveItem.status == 1) {
+					param.videoType = this.liveItem.previewVideoType || ''
+					param.videoId = this.liveItem.previewVideoId || ''
+				}
+				if (this.liveItem.liveType == 1) {
+					param.bufferRate = this.totalTraffic
+				}
+				internetTraffic(param)
+			},
+			scrollToBottom() {
+				this.$nextTick(() => {
+					setTimeout(() => {
+						const query = uni.createSelectorQuery().in(this);
+						// 获取 scroll-view 和内容的高度
+						query.select('.scrolly').boundingClientRect(scrollRect => {
+							query.select('.scrolly').scrollOffset(scrollOffset => {
+								// 计算新的滚动位置
+								const newScrollTop = scrollOffset.scrollHeight - scrollRect
+									.height;
+								this.scrollTop = newScrollTop;
+							}).exec();
+						}).exec();
+					}, 100);
+				});
+			},
+			// 恢复页面活动
+			async resumePageActivity() {
+
+				if (this.liveItem) {
+					await this.getliving(this.liveId)
+					this.startTimeTimer(this.liveItem)
+				}
+				if (!this.isSocketAvailable()) {
+					this.initSocket()
+				}
+			},
+
+
+			// 获取用户专属随机色(缓存机制:同一用户始终用同一颜色)
+			getUserRandomColor(userId) {
+				if (!userId) {
+					return '#8978e2'; // 默认颜色
+				}
+				//如果缓存中已有该用户的颜色,直接返回
+				if (this.userRandomColors[userId]) {
+					return this.userRandomColors[userId];
+				}
+				//为新用户生成固定颜色(基于用户ID生成,不是完全随机)
+				const color = this.generateStableColor(userId);
+				this.userRandomColors[userId] = color;
+				// 存储到本地缓存,确保页面刷新后颜色不变
+				this.saveUserColorsToStorage();
+				return color;
+			}, // 基于用户ID生成稳定颜色(不是完全随机)
+			generateStableColor(userId) {
+				// 将用户ID转换为数字种子
+				let seed = 0;
+				for (let i = 0; i < userId.length; i++) {
+					seed = (seed * 31 + userId.charCodeAt(i)) % 1000000;
+				}
+				const colorPool = [
+					'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
+					'#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9',
+					'#F8C471', '#82E0AA', '#F1948A', '#85C1E9', '#D7BDE2'
+				];
+				return colorPool[seed % colorPool.length];
+			},
+			// 保存颜色映射到本地存储
+			saveUserColorsToStorage() {
+				try {
+					uni.setStorageSync('userRandomColors', this.userRandomColors);
+				} catch (e) {
+					console.warn('保存用户颜色缓存失败:', e);
+				}
+			},
+			// 从本地存储加载颜色映射
+			loadUserColorsFromStorage() {
+				try {
+					const cached = uni.getStorageSync('userRandomColors');
+					if (cached) {
+						this.userRandomColors = cached;
+					}
+				} catch (e) {
+					console.warn('加载用户颜色缓存失败:', e);
+				}
+			},
+			//头像名字
+			getNicknameInitial(nickName) {
+				if (!nickName || typeof nickName !== 'string') return '未';
+				if (/^[\u4e00-\u9fa5]/.test(nickName[0])) {
+					return nickName[0];
+				}
+				return nickName[0].toUpperCase();
+			},
+
+			async getUserInfo() {
+				await getUserInfo().then(
+					res => {
+						if (res.code == 200) {
+							this.userData = res.user;
+
+						} else {
+							uni.showToast({
+								icon: 'none',
+								title: "请求失败",
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+
+			//订阅消息
+			handleAgreement() {
+				const templateId = this.templateId;
+				uni.requestSubscribeMessage({
+					tmplIds: [templateId],
+					success: (res) => {
+						// console.log("模板订阅状态", res[templateId]);
+						if (res[templateId] === "accept") {
+							uni.showToast({
+								title: '订阅成功,开播将提醒您',
+								icon: 'success'
+							});
+							this.callSendMessageApi()
+						} else if (res[templateId] === 'reject') {
+							uni.showToast({
+								title: '您已拒绝订阅,将无法收到提醒',
+								icon: 'none'
+							});
+						} else if (res[templateId] === 'ban') {
+							uni.showToast({
+								title: '您已关闭所有订阅权限,请在设置中开启',
+								icon: 'none'
+							});
+						}
+					},
+					fail: (err) => {
+						console.error('订阅消息失败', err);
+						uni.showToast({
+							title: '订阅失败,请重试',
+							icon: 'none'
+						});
+					}
+				});
+			},
+			async callSendMessageApi() {
+				if (!this.userData.userId) return;
+				const templateData = {
+					taskName: this.liveId,
+					userId: this.userData.userId,
+					templateId: this.templateId, // 模板ID
+					data: {
+						thing6: this.liveItem.liveName,
+						date7: this.liveItem.startTime,
+					}
+				};
+				subNotifyLive(templateData).then(res => {
+						if (res.code == 200) {
+							this.isAgreement = true;
+							uni.setStorageSync('isAgreement', true);
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+
+			//发送心跳
+			sendHeartBeat() {
+				if (!this.isSocketAvailable()) return;
+				try {
+					const heartBeatMsg = JSON.stringify({
+						cmd: "heartbeat",
+						msg: "ping",
+						userId: this.userData.userId || '',
+						liveId: this.liveId
+					});
+					this.socket.send({
+						data: heartBeatMsg,
+						success: () => {
+							this.heartBeatRetryCount = 0; // 成功后重置重试次数
+							this.startPingTimeout(); // 启动超时检测
+						},
+						fail: (err) => {
+							console.error("心跳包发送失败:", err);
+							this.heartBeatRetryCount++;
+							// 心跳失败先重试,重试次数用完再重连
+							if (this.heartBeatRetryCount < this.maxHeartBeatRetries) {
+								setTimeout(() => this.sendHeartBeat(), 2000); // 2秒后重试
+							} else {
+								this.heartBeatRetryCount = 0;
+								this.handleReconnect(); // 重试用完才重连
+							}
+						}
+					});
+				} catch (err) {
+					console.error("心跳发送异常:", err);
+					this.heartBeatRetryCount++;
+					if (this.heartBeatRetryCount < this.maxHeartBeatRetries) {
+						setTimeout(() => this.sendHeartBeat(), 2000);
+					} else {
+						this.heartBeatRetryCount = 0;
+						this.handleReconnect();
+					}
+				}
+			},
+			// 启动心跳超时检测
+			startPingTimeout() {
+				// 清除之前的超时定时器
+				if (this.pingTimeoutTimer) {
+					clearTimeout(this.pingTimeoutTimer);
+					this.pingTimeoutTimer = null;
+				}
+				// 超时后触发重连
+				this.pingTimeoutTimer = setTimeout(() => {
+					// console.error("心跳响应超时,连接异常");
+					this.handleReconnect();
+				}, this.pingTimeout);
+			},
+			stopHeartBeat() {
+				if (this.heartBeatTimer) {
+					clearInterval(this.heartBeatTimer);
+					this.heartBeatTimer = null;
+				}
+				if (this.pingTimeoutTimer) {
+					clearTimeout(this.pingTimeoutTimer);
+					this.pingTimeoutTimer = null;
+				}
+			}, // 封装通用的连接状态校验方法
+			isSocketAvailable() {
+				// WebSocket readyState:0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED
+				return this.socket && this.isSocketOpen && this.socket.readyState === 1;
+			},
+			// 处理重连逻辑
+			handleReconnect() {
+				this.resetReconnectState();
+				// uni.onNetworkStatusChange(res=>{
+				// 	if (res.networkType === 'wifi') {
+
+				// 	}
+				// })
+				this.stopHeartBeat();
+				if (this.reconnectCount < this.maxReconnectAttempts) {
+					this.reconnectCount++;
+					const delay = 1000;
+					console.log(`第${this.reconnectCount}次重连,延迟${delay}ms`);
+
+					this.reconnectTimer = setInterval(() => {
+						this.initSocket();
+					}, delay);
+				} else {
+					console.log(`停止重连(手动关闭/已达最大次数)`);
+					this.closeWebSocket(true);
+				}
+			},
+			// 重置重连状态
+			resetReconnectState() {
+				this.reconnectCount = 0;
+				if (this.reconnectTimer) {
+					clearInterval(this.reconnectTimer);
+					this.reconnectTimer = null;
+				}
+			},
+
+			//输入框
+			inputFocus() {
+				// this.chatHeight = this.keyboardHeight;
+				this.isFocus = true;
+			},
+			inputBlur() {
+				// this.chatHeight = 0;
+				this.isFocus = false
+			},
+			getTimeDifferenceInSeconds(createTimeStr) {
+				const createTime = new Date(createTimeStr.replace(/-/g, '/'));
+				const now = new Date();
+				const timeDiffMs = now - createTime;
+				const timeDiffSeconds = Math.floor(timeDiffMs / 1000);
+				return Math.max(0, timeDiffSeconds);
+			},
+			// 录播时间点
+			onVideoMetaLoaded(e) {
+				this.videoProgressKey = `videoProgress_${this.liveId}`;
+				this.setVideoProgress();
+			},
+			setVideoProgress() {
+				// 只有录播和回放需要设置进度
+				if (this.liveItem.liveType !== 2 && this.liveItem.liveType !== 3) {
+					return;
+				}
+				let currentTime = 0;
+				if (this.liveItem.liveType === 2) {
+					// 录播:计算当前时间与开始时间的差值,对视频总时长取模
+					const diff = this.getTimeDifferenceInSeconds(this.liveItem.startTime);
+					if (diff > this.liveItem.duration) {
+						const storedProgress = uni.getStorageSync(this.videoProgressKey);
+						currentTime = (storedProgress >= this.liveItem.duration) ? 0 : (storedProgress || 0);
+					} else {
+						currentTime = diff % this.liveItem.duration;
+					}
+
+					// currentTime = diff % this.liveItem.duration;
+				} else if (this.liveItem.liveType === 3) {
+					// 回放:从存储中获取进度
+					const storedProgress = uni.getStorageSync(this.videoProgressKey);
+					currentTime = storedProgress || 0;
+				}
+				const videoId = `myVideo_${this.liveId}`;
+				const videoContext = uni.createVideoContext(videoId, this);
+				if (videoContext) {
+					videoContext.seek(currentTime);
+				}
+			},
+
+			onVideoWaiting(e) {
+				// console.log('视频等待加载', e);
+				//流量
+
+				if (this.liveItem.liveType == 2) {
+					this.startTrafficCalculation(this.bitrate);
+				} else {
+					let that = this
+					if (this.trafficInterval) {
+						clearInterval(this.trafficInterval);
+						this.trafficInterval = null;
+					}
+					this.trafficInterval = setInterval(function() {
+						that.getInternetTraffic();
+					}, 10000);
+				}
+			},
+
+			// 视频时间更新
+			onVideoTimeUpdate(e) {
+				// 获取当前播放时间
+				this.videoCurrentTime = e.detail.currentTime;
+				// 每隔5秒保存一次进度(避免频繁存储)
+				if (Math.floor(this.videoCurrentTime) % 5 === 0) {
+					this.saveVideoProgress();
+				}
+				// this.setVideoProgress();
+			},
+
+			// 视频暂停
+			onVideoPause(e) {
+				if (this.liveItem.liveType === 2) {
+					const videoId = `myVideo_${this.liveId}`;
+					const videoContext = uni.createVideoContext(videoId, this);
+					setTimeout(() => {
+						videoContext.play();
+					}, 100);
+				}
+				// 暂停时保存进度
+				this.saveVideoProgress();
+			},
+
+			// 视频播放
+			onVideoPlay(e) {},
+			// 设置视频当前时间
+			// setVideoCurrentTime(time) {
+			// 	if (!time) return;
+			// 	const videoId = `myVideo_${this.liveId}`;
+			// 	const videoContext = uni.createVideoContext(videoId, this);
+
+			// 	if (videoContext) {
+			// 		videoContext.seek(time);
+			// 		console.log(`设置视频播放位置: ${time}秒`);
+			// 	}
+			// },
+
+			// 保存视频进度
+			saveVideoProgress() {
+				if (this.videoProgressKey) {
+					uni.setStorage({
+						key: this.videoProgressKey,
+						data: this.videoCurrentTime,
+						success: () => {},
+						fail: (err) => {
+							console.error('保存视频进度失败:', err);
+						}
+					});
+				}
+			},
+
+			// 点击红包
+			onRed() {
+				if (!this.liveId) return;
+				if (!this.redInfo?.redId) return;
+				if (this.redTimer) {
+					clearInterval(this.redTimer);
+					this.redTimer = null;
+				}
+				let data = {
+					liveId: this.liveId,
+					userId: this.userData.userId,
+					redId: this.redInfo.redId,
+				}
+				liveRed(data).then(res => {
+						this.isShowRed = false
+						this.redCard = res
+						this.isShowRedCard = true
+					},
+					rej => {}
+				);
+			},
+			//领取优惠券
+			onCoupon() {
+				if (!this.couponInfo.couponIssueId) return;
+
+				let data = {
+					goodsId: this.couponInfo.goodsId,
+					couponIssueId: this.couponInfo.couponIssueId,
+					liveId: this.liveId
+				};
+				coupon(data)
+					.then(res => {
+						this.isShowCoupon = false
+						if (res.code == 200) {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+
+						}
+					})
+					.catch(rej => {});
+			},
+
+
+			// 我的中奖名单
+			getMyLottery() {
+				this.winning = true
+				myLottery().then(res => {
+						if (res.code == 200) {
+							console.log("我的中奖名单", res)
+							this.prizeAll = res.data.list || {};
+
+						} else {
+
+						}
+					})
+					.catch(rej => {});
+			},
+			// 抽奖
+			onLottery() {
+				if (!this.lotteryInfo) return;
+
+				let data = {
+					lotteryId: this.lotteryInfo.lotteryId
+				};
+
+				liveLottery(data)
+					.then(res => {
+						if (res.code == 200) {
+							const resData = res.data || {};
+							this.lotteryList = Array.isArray(resData) ? resData : [];
+							this.lotteryProducts = Array.isArray(resData.products) ? resData.products : [];
+
+							if (resData.duration) {
+								this.isShowLotteryPop = true;
+							}
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+							this.lotteryList = [];
+							this.lotteryProducts = [];
+						}
+					})
+					.catch(rej => {
+						uni.showToast({
+							title: '获取抽奖信息失败',
+							icon: 'none'
+						});
+						// 失败时强制重置为数组
+						this.lotteryList = [];
+						this.lotteryProducts = [];
+					});
+			},
+			// 参与抽奖
+			onClaim() {
+				let data = {
+					liveId: this.liveId,
+					lotteryId: this.lotteryInfo.lotteryId,
+				}
+				claim(data).then(res => {
+						if (res.code == 200) {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+							this.isShowLotteryPop = false
+							this.havePrize = true
+							uni.setStorageSync('havePrize', this.havePrize);
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			confirm() {
+				this.isShowPrize = false;
+				this.havePrize = false;
+				uni.setStorageSync('havePrize', this.havePrize);
+			},
+			// 商品收藏
+			onGoodsCollect(item) {
+				if (!item || item.length === 0 || !item.goodsId) {
+					return;
+				}
+				collectGoods(item.goodsId).then(res => {
+						if (res.code == 200) {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+							item.isFavorite = !item.isFavorite
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+
+			//正在购买
+			getliveOrder(item) {
+				if (!this.liveId) {
+					return;
+				}
+				liveOrderUser(this.liveId).then(res => {
+						if (res.code == 200) {
+							this.orderUser = res;
+						} else {
+							console.log('获取正在购买用户失败');
+						}
+					},
+					rej => {}
+				);
+			},
+			onLiveStateChange(e, liveItem) {
+				// 可以根据状态码处理不同的直播状态
+				const stateCode = e.detail.code;
+				if (e.detail.code == -2301 || e.detail.code == -2302) {
+					this.playVideo()
+				} else if (e.detail.code == 2004) {
+					this.calculateTimeDiff(this.liveItem)
+					this.startTrafficCalculation(this.bitrateLive);
+				}
+				// 2001: 已经连接服务器
+				// 2002: 已经连接服务器,开始拉流
+				// 2003: 网络接收到首个视频数据包(IDR)
+				// 2004: 视频播放开始
+				// 2005: 视频播放进度
+				// 2006: 视频播放结束
+				// 2007: 视频播放Loading
+				// 2008: 解码器启动
+				// -2301: 网络断连,且经多次重连抢救无效,更多重试请自行重启播放
+				// -2302: 获取加速拉流地址失败
+			}, // 直播错误事件
+			onLiveError(e, liveItem) {
+				this.videoError(e, liveItem);
+				console.log('错误');
+			},
+			//  红包 卡片 抽奖
+			getCurrentActivities() {
+				if (!this.liveId) return;
+				currentActivities(this.liveId).then(res => {
+					if (res.code === 200) {
+						// 提取数据(默认空数组/对象避免报错)
+						this.redInfo = (Array.isArray(res.red) ? res.red : [])[0] || {};
+						this.lotteryInfo = (Array.isArray(res.lottery) ? res.lottery : [])[0] || {};
+						this.goodsCard = res.goods || {};
+
+
+						this.isShowGoods = this.goodsCard && this.goodsCard.status == 1;
+						this.isShowRed = this.redInfo && this.redInfo.redStatus == 1;
+						this.isShowLottery = this.lotteryInfo && this.lotteryInfo.lotteryStatus == 1;
+						if (this.isShowRed) {
+							this.redTimer = setInterval(() => {
+								const redCountdown = this.handleTime(this.redInfo.updateTime, this.redInfo
+									.duration)
+								if (!redCountdown) {
+									this.isShowRed = false
+									clearInterval(this.redTimer)
+								}
+							}, 1000);
+						}
+						// 处理抽奖定时器
+						if (this.isShowLottery) {
+							this.lotteryTimer = setInterval(() => {
+								this.countdown = this.handleTime(this.lotteryInfo.updateTime, this
+									.lotteryInfo
+									.duration)
+							}, 1000);
+						}
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+					}
+				}, rej => {});
+
+			},
+
+			// 计算当前时间与 liveItem.startTime 的差值,并更新 totalTime
+			calculateTimeDiff(item) {
+				if (!item.startTime) return;
+				// 提取对应场景的时间字符串(直播用startTime,抽奖用updateTime)
+				let timeStr = item.startTime;
+
+				// 转换时间格式(适配iOS,将 "-" 替换为 "/")
+				const time = new Date(timeStr.replace(/-/g, "/"));
+
+				if (isNaN(time.getTime())) {
+					return;
+				}
+				const now = new Date();
+				let diffMs = Math.max(0, now.getTime() - time.getTime())
+				// 转换为 时:分:秒(补零处理)
+				const totalSeconds = Math.floor(diffMs / 1000);
+				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.$set(this.liveItem, "diffMs", diffMs);
+				this.$set(this.liveItem, "totalSeconds", totalSeconds);
+			},
+
+			padZero(num) {
+				return num < 10 ? `0${num}` : num;
+			},
+			// 启动当前直播间的时间差值定时器
+			startTimeTimer(item) {
+				if (!item) return;
+				// 立即计算一次(避免等待1秒才显示)
+				const totalTime = this.calculateTimeDiff(item);
+				item.timeTimer = setInterval(() => {
+					const totalTime = this.calculateTimeDiff(item);
+				}, 1000);
+
+			},
+
+			toggleViewerList() {
+				const now = Date.now();
+				if (now - this.lastClickTime > this.clickDelay) {
+					this.showadd = !this.showadd;
+					if (this.showadd) {
+						this.getliveUser(false); // 加载第一页观众
+					}
+					this.lastClickTime = now;
+				}
+			},
+			// 播放视频
+			playVideo() {
+				if (!this.liveItem) {
+					console.log('liveItem 为空,无法播放视频');
+					return;
+				}
+				try {
+					// 直播流使用live-player
+					if (this.liveItem.liveType === 1 && this.liveItem.livingUrl && this.liveItem.status == 2) {
+						const livePlayerId = `myLivePlayer_${this.liveId}`;
+						const livePlayerContext = uni.createLivePlayerContext(livePlayerId, this);
+						// console.log("直播")
+						if (livePlayerContext) {
+							livePlayerContext.play();
+						}
+					} else if (this.liveItem.status == 1 && this.liveItem.previewUrl) {
+						const videoId = `myVideo_${this.liveId}`;
+						const videoContext = uni.createVideoContext(videoId, this);
+
+						if (videoContext) {
+							videoContext.play();
+						}
+					} else if (this.liveItem.liveType === 2 && this.liveItem.videoUrl && this.liveItem.status == 2) {
+						const videoId = `myVideo_${this.liveId}`;
+						const videoContext = uni.createVideoContext(videoId, this);
+						// console.log("录播")
+						if (videoContext) {
+							videoContext.play();
+						}
+					} // 回放视频使用video
+					else if (this.liveItem.liveType === 3 && this.liveItem.videoUrl && this.liveItem.status == 4) {
+						const videoId = `myVideo_${this.liveId}`;
+						const videoContext = uni.createVideoContext(videoId, this);
+						// console.log("回放")
+						if (videoContext) {
+							videoContext.play();
+						}
+					}
+				} catch (error) {
+					console.error("播放视频失败:", error);
+				}
+			},
+
+			pauseVideo() {
+				if (!this.liveItem) return;
+
+				try {
+					// 直播流使用live-player
+					if (this.liveItem.status == 1) {
+						const videoId = `myVideo_${this.liveId}`;
+						const videoContext = uni.createVideoContext(videoId, this);
+						if (videoContext) {
+							videoContext.pause();
+						}
+					} else if (this.liveItem.status == 2) {
+						if (this.liveItem.liveType === 1) {
+							const livePlayerId = `myLivePlayer_${this.liveId}`;
+							const livePlayerContext = uni.createLivePlayerContext(livePlayerId, this);
+							if (livePlayerContext) {
+								livePlayerContext.pause();
+							}
+						} else if (this.liveItem.liveType === 2) {
+							const videoId = `myVideo_${this.liveId}`;
+							const videoContext = uni.createVideoContext(videoId, this);
+							if (videoContext) {
+								videoContext.pause();
+							}
+						}
+					}
+				} catch (error) {
+					console.error("暂停视频失败:", error);
+				}
+			},
+			// 视频错误处理
+			videoError(e, liveItem) {
+				if (!liveItem || !this.liveId) return;
+				// 初始化重试计数
+				if (this.videoRetryCounts[liveItem.liveId] === undefined) {
+					this.videoRetryCounts[liveItem.liveId] = 0;
+				}
+				// 限制重试次数
+				if (this.videoRetryCounts[liveItem.liveId] >= 3) {
+					console.error(`直播间 ${this.liveId} 视频加载失败,停止重试`);
+					// 显示错误提示
+					uni.showToast({
+						title: "视频加载失败,请检查网络",
+						icon: 'none',
+						duration: 2000
+					});
+					return;
+				}
+
+				this.videoRetryCounts[this.liveId]++;
+
+				// 延迟重试
+				setTimeout(() => {
+					if (this.liveId === this.liveId) {
+						console.log(`第${this.videoRetryCounts[this.liveId]}次重试播放视频`);
+						this.playVideo();
+					}
+				}, 2000);
+			},
+
+
+
+			openViews() {
+				// 计算scroll-view高度
+				this.$nextTick(() => {
+					const query = uni.createSelectorQuery().in(this);
+					query.select('.view-box').boundingClientRect(data => {
+						if (data) {
+							this.scrollHeight = data.height - 80 ; // 80是标题高度,120是底部高度
+						}
+					}).exec();
+				});
+			},
+			// 滚动到底部触发
+			handleScrollToLower() {
+				// 清除上一次未执行的定时器,避免重复请求
+				if (this.scrollTimer) {
+					clearTimeout(this.scrollTimer);
+				}
+				// 延迟0.5秒(500毫秒)执行接口请求
+				this.scrollTimer = setTimeout(() => {
+					this.getliveUser(true);
+				}, 1000);
+			},
+			async getLiveMsg(liveItem) {
+				if (!liveItem || !this.liveId) {
+					console.error('getLiveMsg 错误:无效的 liveItem');
+					return;
+				}
+				try {
+					const res = await liveMsg(this.liveId, 30, 1);
+					if (res.code == 200) {
+						const rows = Array.isArray(res.rows) ? res.rows : [];
+						const reversedTalkList = [...rows].reverse();
+						this.talklist = Array.isArray(reversedTalkList) ? reversedTalkList : [];
+						// 获取历史消息后也滚动到底部
+						this.$nextTick(() => {
+							this.scrollToBottom();
+						});
+					} else {
+						this.talklist = [];
+					}
+				} catch (error) {
+					this.talklist = [];
+					console.error("获取聊天记录失败:", error);
+				}
+			},
+			generateRandomChineseName() {
+				const prefixes = [
+					'幸福', '快乐', '安康', '吉祥', '如意', '平安', '健康', '长寿',
+					'福气', '美满', '和谐', '团圆', '富贵', '荣华', '宁静', '淡泊',
+					'知足', '常乐', '悠然', '自在', '夕阳', '晚霞', '金秋', '银发',
+					'老顽童', '开心', '笑口常开', '岁月静好', '云淡风轻', '海阔天空'
+				];
+
+				const suffixes = [
+					'老人', '大爷', '大妈', '爷爷', '奶奶', '伯伯', '阿姨', '前辈',
+					'先生', '女士', '长者', '翁', '婆', '哥', '姐', '友',
+					'客', '迷', '粉丝', '达人', '爱好者', '之家', '之人', '之心',
+					'之情', '之乐', '之旅', '之梦', '之歌', '之韵'
+				];
+
+				const specialNames = [
+					'老有所乐', '知足常乐', '笑看人生', '云淡风轻', '岁月如歌',
+					'夕阳红', '金色年华', '老当益壮', '鹤发童颜', '老骥伏枥',
+					'闲云野鹤', '淡泊明志', '宁静致远', '随遇而安', '顺其自然',
+					'老来俏', '开心果', '老宝贝', '不老松', '常青树'
+				];
+
+				// 30%概率使用特殊网名,70%使用前缀+后缀组合
+				if (Math.random() < 0.3) {
+					return specialNames[Math.floor(Math.random() * specialNames.length)];
+				} else {
+					const prefix = prefixes[Math.floor(Math.random() * prefixes.length)];
+					const suffix = suffixes[Math.floor(Math.random() * suffixes.length)];
+					return prefix + suffix;
+				}
+			},
+			// 获取直播间用户
+			async getliveUser(isLoadMore = false) {
+				this.viewLoading = true;
+				try {
+					const res = await watchUserList(this.liveId, this.viewPageSize, this.viewPageNum, false);
+					if (res.code === 200) {
+						const userRows = Array.isArray(res.rows) ? res.rows : [];
+
+						let array = userRows.map(item => ({
+							avatar: item.avatar || '',
+							userId: item.userId || '',
+							nickName: item.nickName || '未命名'
+						}));
+
+						// 虚拟数据
+						let virtualData = []
+						let virtualTotal = res.total * 2 + 50
+						this.liveUserTotal = virtualTotal
+						for (let i = 0; i < virtualTotal; i++) {
+							let data = {
+								avatar: '',
+								userId: '8565' + i,
+								nickName: this.generateRandomChineseName()
+							}
+							virtualData.push(data)
+						}
+						this.liveViewersData = [...array, ...virtualData]
+
+						const newRows = Array.isArray(res.rows) ? res.rows : [];
+						const currentViewers = Array.isArray(this.liveViewers) ? this.liveViewers : [];
+
+						let viewlist = isLoadMore ? [...currentViewers, ...newRows] : newRows;
+						this.liveViewers = [...viewlist, ...virtualData]
+						this.viewPageNum++;
+					}
+				} catch (error) {
+					console.error('获取观众列表失败:', error);
+				} finally {
+					this.viewLoading = false;
+				}
+			},
+
+			//小黄车搜索商品
+			handleSearchInput() {
+				// 使用防抖优化性能,避免频繁请求
+				clearTimeout(this.searchTimer);
+				this.searchTimer = setTimeout(() => {
+					this.queryCollect();
+				}, 500); // 500毫秒延迟
+			},
+
+
+			// 显示购买提示信息
+			showPurchaseMessage() {
+				// 清除之前的定时器
+				if (this.purchasePromptTimer) {
+					clearTimeout(this.purchasePromptTimer);
+				}
+
+				// 显示提示
+				this.showPurchasePrompt = true;
+
+				// 2秒后自动隐藏
+				this.purchasePromptTimer = setTimeout(() => {
+					this.showPurchasePrompt = false;
+				}, 2000);
+			},
+
+			//名字超过省略
+			truncateString(str, maxLength) {
+				if (typeof str !== 'string' || str.length <= maxLength) {
+					return str;
+				}
+				return str.slice(0, maxLength) + '...'; // 截断后加省略号
+			},
+			// 跳转页面
+			navgetTo(url) {
+				uni.navigateTo({
+					url: url
+				})
+			},
+
+			// 修改获取直播信息方法
+			async getliving(liveId) {
+				if (!liveId) return;
+				const param = {
+					id: liveId
+				};
+				try {
+					const res = await getlive(param);
+					if (res.code !== 200) {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+						return;
+					}
+					this.liveItem = Object.assign({}, this.liveItem, res.data);
+					// this.talklist = Array.isArray((res.data || {}).talklist) ? res.data.talklist : [];
+					this.startTimeTimer(this.liveItem);
+					// 清除旧定时器(如预告倒计时)
+					if (this.liveStartTimer) {
+						clearInterval(this.liveStartTimer);
+						this.liveStartTimer = null;
+					}
+					if (res.data.status == 1) {
+						// 直播预告
+						this.liveStartTimer = setInterval(async () => {
+							this.liveCountdown = this.handleTime(res.data.startTime, 0);
+							if (!this.liveCountdown) {
+								uni.removeStorageSync('isAgreement');
+								await this.getliving(this.liveId);
+								clearInterval(this.liveStartTimer);
+							}
+						}, 1000);
+
+						this.$set(this.liveItem, 'previewUrl', res.data.previewUrl);
+						this.$set(this.liveItem, 'livingUrl', ''); // 清空直播流
+						this.$set(this.liveItem, 'videoUrl', ''); // 清空回放视频
+					} else if (res.data.status == 2) {
+						if (res.data.liveType == 1) {
+							// 直播流
+							let cTime = Math.floor(Math.random() * 10000) + 1;
+							let livingUrl = res.data.flvHlsUrl + "&t=" + cTime;
+							console.log("地址在", this.liveItem.livingUrl)
+							this.$set(this.liveItem, 'livingUrl', livingUrl);
+							this.$set(this.liveItem, 'videoUrl', ''); // 清空回放视频
+						} else if (res.data.liveType === 2) {
+							// 回放视频   2录播 3直播回放
+							// let urlStr = 'https://fs-1319721001.cos.ap-chongqing.myqcloud.com/10%E6%9C%8820%E6%97%A5%20%281%29.m3u8'
+							// this.$set(this.liveItem, 'videoUrl', urlStr);
+							this.$set(this.liveItem, 'videoUrl', res.data.videoUrl);
+							this.$set(this.liveItem, 'livingUrl', '');
+						}
+					} else if (res.data.status == 4 && res.data.liveType == 3) {
+						this.$set(this.liveItem, 'videoUrl', res.data.videoUrl);
+						this.$set(this.liveItem, 'livingUrl', '');
+					} else {
+						// 未开播
+						this.$set(this.liveItem, 'livingUrl', '');
+						this.$set(this.liveItem, 'videoUrl', '');
+					}
+					this.$set(this.liveItem, 'autoplay', res.data.liveType !== 0);
+					this.$set(this.liveItem, 'showType', res.data.showType);
+					this.storeId = res.storeId;
+					//  启动“30秒刷新直播间数据”的定时器
+					this.startLiveViewDataTimer();
+					this.playVideo();
+				} catch (err) {
+					console.error("获取直播信息失败:", err);
+					uni.showToast({
+						title: "获取直播信息失败",
+						icon: 'none'
+					});
+				}
+			},
+
+			getPureDecimal(num, precision = 6) {
+				const decimalPart = Math.abs(num).toFixed(precision).split('.')[1];
+				return decimalPart?.replace(/0+$/, '') || ''; // 移除末尾多余的0
+			},
+			goBack() {
+				// 暂停当前视频
+				if (this.liveItem) {
+					this.pauseVideo();
+				}
+				// 关闭WebSocket连接
+				this.closeWebSocket(true);
+				// 导航返回
+				const pages = getCurrentPages();
+				if (pages.length > 1) {
+					uni.navigateBack();
+				} else {
+					uni.reLaunch({
+						url: '/pages_course/livingList'
+					});
+				}
+			},
+			// 点赞
+			async onLike() {
+				if (!this.liveId) return;
+				try {
+					const res = await liveDataLike(this.liveId);
+					if (res?.like) {
+						this.liveViewData.like++; // 只更新当前直播间的点赞数
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+					}
+				} catch (error) {
+					console.error('点赞失败:', error);
+				}
+			},
+
+			//直播间点赞、关注、在线人数数据
+			getliveViewData(liveItem) {
+				if (!liveItem || !this.liveId) return;
+
+				getLiveViewData(this.liveId).then(res => {
+					if (res.code == 200) {
+						// 强制响应式更新,确保数据实时显示
+						this.liveViewData = res;
+					}
+				}).catch(error => {
+					console.error("获取直播间数据失败:", error);
+					// 失败时兜底,避免显示异常
+					this.liveViewData = {
+						like: 0,
+						watchCount: 0
+					};
+				});
+			},
+			// 30秒刷新一下直播间点赞数
+			startLiveViewDataTimer() {
+				// 先清除旧定时器(防止重复创建)
+				if (this.liveViewDataTimer) {
+					clearInterval(this.liveViewDataTimer);
+					this.liveViewDataTimer = null;
+				}
+				// 启动新定时器,每3秒执行一次
+				this.liveViewDataTimer = setInterval(() => {
+					// 安全校验:确保liveItem和liveId存在(避免无效请求)
+					if (this.liveItem && this.liveId) {
+						this.getliveViewData(this.liveItem);
+					}
+				}, 30000);
+			},
+			// 去购买,跳商品详情
+			goShop(productId, goodsId) {
+				if (!this.liveId) return;
+				uni.navigateTo({
+					url: '/pages_shopping/live/goods?productId=' + productId + '&liveId=' + this.liveId +
+						'&goodsId=' +
+						goodsId + '&storeId=' + this.storeId
+				})
+			},
+
+			// 查询店铺
+			async queryCollect() {
+				this.loadingProducts = true;
+				if (!this.liveId) return;
+				if (this.inputInfo == null) this.inputInfo = ''
+				uni.showLoading({
+					title: '加载中'
+				});
+				try {
+					const res = await liveStore(this.liveId, this.inputInfo);
+					uni.hideLoading()
+					this.shopping = true
+					if (res.code === 200) {
+						// 数据绑定到当前 liveItem,避免全局污染
+						this.products = Array.isArray(res.data) ? res.data : [];
+					}
+				} catch (error) {
+					console.error('获取小黄车商品失败:', error);
+				} finally {
+					this.loadingProducts = false;
+				}
+			},
+			// 时间戳
+			initTime() {
+				const now = new Date();
+				this.timestamp = now.getTime();
+			},
+
+			openCart() {
+				this.queryCollect()
+
+			},
+			close() {
+				this.showadd = false
+			},
+
+			// 关闭小黄车
+			closeShop() {
+				this.shopping = false;
+			},
+			closeMore() {
+				this.isMore = false;
+			},
+			closeWin() {
+				this.winning = false;
+			},
+			// 关闭WebSocket连接(isManual:是否手动关闭)
+			closeWebSocket(isManual = true) {
+				if (!this.socket || !this.isSocketOpen) {
+					console.warn("WebSocket 任务不存在或未打开,无需关闭");
+					return;
+				}
+				// console.log("websocket 连接关闭");
+				this.isManualClose = isManual;
+				this.stopHeartBeat();
+				this.resetReconnectState();
+				try {
+					// 先保存引用,避免在关闭过程中被置为null
+					const socketToClose = this.socket;
+					this.socket = null;
+					this.isSocketOpen = false;
+
+					socketToClose.close({
+						code: 1000,
+						reason: isManual ? "主动关闭" : "异常关闭"
+					});
+					console.log("WebSocket连接已发起关闭");
+				} catch (err) {
+					console.error("关闭WebSocket失败:", err);
+					// 即使关闭失败,也要重置状态
+					this.socket = null;
+					this.isSocketOpen = false;
+				}
+			},
+			startHeartBeat() {
+				this.stopHeartBeat(); // 先停止现有心跳,防止重复
+				this.sendHeartBeat(); // 立即发送一次心跳
+				// 按间隔循环发送心跳
+				this.heartBeatTimer = setInterval(() => {
+					this.sendHeartBeat();
+				}, this.heartBeatInterval);
+			},
+			initSocket() {
+
+				if (this.isConnecting) {
+					return;
+				}
+				// 如果已经存在连接且状态为open,则退出
+				if (this.socket && this.socket.readyState === 1) {
+					return;
+				}
+				if (this.socket && (this.socket.readyState === 0 || this.socket.readyState === 1)) {
+					console.log('关闭现有WebSocket连接,创建新连接');
+					this.closeWebSocket(true);
+				}
+				// 校验必要参数
+				if (!this.liveId) {
+					console.error("缺失直播间ID,无法初始化WebSocket");
+					return;
+				}
+				if (!this.userData || !this.userData.userId) {
+					console.error("用户信息缺失,无法初始化WebSocket");
+					return;
+				}
+				// 清除之前的重连定时器
+				this.resetReconnectState();
+
+				const now = new Date();
+				this.timestamp = now.getTime(); // 生成签名
+				const signature = CryptoJS.HmacSHA256(
+					`${this.liveId}${this.userData.userId}${this.userType}${this.timestamp}`,
+					this.timestamp.toString()
+				).toString(CryptoJS.enc.Hex);
+
+				try {
+					const baseWsUrl = 'wss://api.fhhx.runtzh.com/ws/app/webSocket';
+					// const baseWsUrl = 'ws://192.168.10.166:7114/ws/app/webSocket';
+					let wsUrl =
+						`${baseWsUrl}?userId=${this.userData.userId}&liveId=${this.liveId}&userType=${this.userType}&timestamp=${this.timestamp}&signature=${signature}`;
+					if (this.qrFrom) {
+						wsUrl += this.qrFrom;
+					}
+					const socketTask = uni.connectSocket({
+						url: wsUrl,
+						success: () => {
+							// console.log("Socket连接请求发送成功")
+						},
+						fail: (err) => {
+							console.error("Socket连接请求失败:", err);
+							this.handleReconnect();
+						}
+					});
+
+					// 连接打开事件
+					socketTask.onOpen((res) => {
+						// console.log("WebSocket连接已打开");
+						this.socket = socketTask;
+						this.isConnecting = false;
+						this.isSocketOpen = true;
+						this.reconnectCount = 0;
+						this.resetReconnectState();
+						this.heartBeatRetryCount = 0; // 重置心跳重试次数
+						this.shownEntryUsers.clear(); // 重连后重置进入提示记录
+						this.startHeartBeat();
+					});
+
+					// 消息接收事件
+					socketTask.onMessage((res) => {
+						try {
+							const data = JSON.parse(res.data);
+							// 处理服务端心跳响应
+							if (data.cmd === "heartBeatAck") {
+								this.stopHeartBeat(); // 清除当前超时检测
+								this.startHeartBeat(); // 重新启动心跳周期
+								return;
+							}
+							this.handleSocketMessage(res);
+						} catch (err) {
+							console.error("消息解析异常:", err);
+						}
+					});
+					// 连接错误事件
+					socketTask.onError((err) => {
+						console.error("WebSocket连接错误:", err);
+						this.isSocketOpen = false;
+						this.stopHeartBeat();
+						this.isConnecting = false;
+						this.handleReconnect(); // 错误直接触发重连
+					});
+					// 连接关闭事件
+					socketTask.onClose((res) => {
+						console.log("WebSocket连接关闭:", res);
+						this.isSocketOpen = false;
+						this.isConnecting = false;
+						this.stopHeartBeat(); // 清除心跳定时器
+						if (!this.isManualClose && this.reconnectCount < this.maxReconnectAttempts) {
+							this.handleReconnect();
+						} else {}
+					});
+				} catch (e) {
+					console.error("创建WebSocket异常:", e);
+					this.handleReconnect();
+				}
+			},
+			handleTime(time, duration) {
+				// 将time转换为毫秒级时间戳
+				let timeStamp;
+				// 如果time是数字且合理(毫秒级时间戳通常为13位左右的正数),视为有效时间戳
+				if (typeof time === 'number' && time > 0 && time < 9999999999999) {
+					timeStamp = time;
+				}
+				//如果是字符串,尝试解析为日期后转为时间戳
+				else if (typeof time === 'string' && time.trim() !== '') {
+					// 处理兼容性:将"2025-09-25 17:30:00"转为ISO格式"2025-09-25T17:30:00"
+					const isoTime = time.replace(' ', 'T');
+					const date = new Date(isoTime);
+					// 校验日期是否有效
+					if (!isNaN(date.getTime())) {
+						timeStamp = date.getTime();
+					} else {
+						console.error('无效的日期格式:', time);
+						return false; // 格式错误时返回false
+					}
+				} else {
+					console.error('time参数必须是有效的时间戳(数字)或日期字符串');
+					return false;
+				}
+				// 后续逻辑保持不变(基于转换后的timeStamp计算)
+				const targetTimestamp = timeStamp + duration * 60 * 1000;
+				const currentTimestamp = new Date().getTime();
+				const timeDiffMs = targetTimestamp - currentTimestamp;
+
+				if (timeDiffMs <= 0) {
+					return false;
+				}
+
+				const hours = Math.floor(timeDiffMs / (1000 * 60 * 60));
+				const minutes = Math.floor((timeDiffMs % (1000 * 60 * 60)) / (1000 * 60));
+				const seconds = Math.floor((timeDiffMs % (1000 * 60)) / 1000);
+
+				const formatNum = (num) => num.toString().padStart(2, "0");
+				return {
+					hours: formatNum(hours),
+					minutes: formatNum(minutes),
+					seconds: formatNum(seconds)
+				};
+			},
+			// 处理Socket消息
+			async handleSocketMessage(message) {
+				let data = JSON.parse(message.data)
+				const socketMessage = data.data // 服务端返回的消息体
+				if (data.code == 200) {
+					const messageData = {
+						...socketMessage,
+						cmd: socketMessage.cmd || '', // 确保cmd字段存在
+						ts: Date.now() // 时间戳
+					};
+
+					// 处理服务端返回的sendMsg消息,加入本地列表
+					if (socketMessage.cmd == 'sendMsg') {
+						if (!this.isSocketAvailable()) {
+							uni.showToast({
+								title: '连接已断开,正在重试...',
+								icon: 'none'
+							});
+							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();
+					} else if (socketMessage.cmd == 'red') {
+						const redData = socketMessage.data ? JSON.parse(socketMessage.data) : {};
+						this.redInfo = redData || {};
+						this.isShowRed = socketMessage.status === 1;
+						if (this.isShowRed) {
+							this.redTimer = setInterval(() => {
+								const redCountdown = this.handleTime(this.redInfo.updateTime, this.redInfo
+									.duration)
+
+								if (!redCountdown) {
+									this.isShowRed = false
+									clearInterval(this.redTimer)
+								}
+							}, 1000);
+						}
+
+					} else if (socketMessage.cmd == 'goods') {
+						const goodsData = socketMessage.data ? JSON.parse(socketMessage.data) : {};
+						this.goodsCard = goodsData || {};
+						this.isShowGoods = socketMessage.status == 1;
+
+					} else if (socketMessage.cmd == 'coupon') {
+						const couponData = socketMessage.data ? JSON.parse(socketMessage.data) : {};
+						this.couponInfo = couponData || {};
+						this.isShowCoupon = socketMessage.status === 1;
+						if (this.isShowCoupon) {}
+
+					} else if (socketMessage.cmd == 'lottery') {
+
+						const lotteryData = socketMessage.data ? JSON.parse(socketMessage.data) : {};
+						this.lotteryInfo = lotteryData || {};
+						this.isShowLottery = socketMessage.status === 1;
+						if (socketMessage.status != 1) {
+							this.isShowLotteryPop = false
+						}
+						// 清除已有定时器(无论状态是否为1,先清掉旧的)
+						clearTimeout(this.lotteryTimer);
+
+						if (this.isShowLottery) {
+							this.lotteryTimer = setInterval(() => {
+								this.countdown = this.handleTime(this.lotteryInfo.updateTime, this.lotteryInfo
+									.duration)
+								if (!this.countdown) {
+									console.log("倒计时", this.countdown)
+									this.isShowLottery = false;
+									this.isShowLotteryPop = false;
+									clearInterval(this.lotteryTimer)
+								}
+							}, 1000);
+
+
+						} else {
+							this.isShowLottery = false
+						}
+					} else if (socketMessage.cmd == 'entry') {
+						try {
+							if (!this.liveUserCalled) {
+								await this.getliveUser(false);
+								this.liveUserCalled = true;
+							}
+							const userIdToEntry = socketMessage.userId;
+							const existingIndex = this.liveViewersData.findIndex(item => item.userId ===
+								userIdToEntry);
+
+							if (existingIndex === -1) {
+								const liveViewers = {
+									userId: socketMessage.userId,
+									nickName: socketMessage.nickName,
+									avatar: socketMessage.avatar
+								}
+								this.liveViewersData.push(liveViewers);
+								this.liveUserTotal++;
+							}
+
+							// 解析用户ID(根据实际接口字段调整,此处假设data含userId)
+							const userData = JSON.parse(socketMessage.data || '{}');
+							const userId = userData.userId || socketMessage.userId; // 兼容不同字段
+							if (!userId) return; // 无用户ID不处理
+
+							// 仅新用户(未显示过)才触发提示
+							if (!this.shownEntryUsers.has(userId)) {
+								this.inAndOut = socketMessage;
+								this.showWelcomeMessage = true;
+								this.shownEntryUsers.add(userId); // 加入已显示集合
+
+								// 3秒后隐藏提示(可调整时长)
+								if (this.welcomeTimer) clearTimeout(this.welcomeTimer);
+								this.welcomeTimer = setTimeout(() => {
+									this.showWelcomeMessage = false;
+								}, 3000);
+							}
+						} catch (err) {
+							console.error("解析entry用户数据失败:", err);
+						}
+					} else if (socketMessage.cmd == 'out') {
+						if (this.liveUserTotal > 0) {
+							const userIdToRemove = socketMessage.userId;
+							const index = this.liveViewersData.findIndex(item => item.userId === userIdToRemove);
+							if (index !== -1) {
+								this.liveViewersData.splice(index, 1);
+								this.liveUserTotal--; // 根据userId删除对应的用户数据
+							}
+						}
+						this.inAndOut = socketMessage;
+						this.showWelcomeMessage = true;
+
+						// 3秒后隐藏提示
+						if (this.welcomeTimer) clearTimeout(this.welcomeTimer);
+						this.welcomeTimer = setTimeout(() => {
+							this.showWelcomeMessage = false;
+						}, 3000);
+					} else if (socketMessage.cmd == 'live_start' || socketMessage.cmd ==
+						'live_end') {
+
+						// 开始直播,关闭直播
+						if (this.liveStartTimer) {
+							clearInterval(this.liveStartTimer);
+							this.liveStartTimer = null;
+						}
+						if (this.redTimer) {
+							clearInterval(this.redTimer);
+							this.redTimer = null;
+						}
+						//  请求最新直播间数据
+						await this.getliving(this.liveId); // 注意:需用 await 确保数据更新完成
+
+						//  强制触发视图更新(兜底方案,若上述步骤仍不生效)
+						// this.$forceUpdate(); 
+
+					} else if (socketMessage.cmd == 'Integral') {
+						this.integral = {
+							msg: socketMessage.msg,
+							status: true
+						}
+					} else if (socketMessage.cmd == 'LotteryDetail') {
+						try {
+							this.prizeInfo = Array.isArray(JSON.parse(socketMessage.data || '[]')) ?
+								JSON.parse(socketMessage.data || '[]') : [];
+						} catch (err) {
+							console.error('解析抽奖结果失败:', err);
+							this.prizeInfo = [];
+						}
+						this.isShowPrize = true;
+						this.isShowLottery = false;
+						this.isShowLotteryPop = false;
+					} else if (socketMessage.cmd == 'blockUser') {
+						uni.removeStorage({
+							key: 'AppToken',
+							success: () => {
+								uni.reLaunch({
+									url: '/pages/auth/login'
+								});
+							}
+						});
+					}
+				} else {
+					uni.showToast({
+						title: data.msg,
+						icon: 'none'
+					});
+				}
+			},
+			sendMsg(retries = 1) {
+				// 防止连续点击发送两次(短时锁定)
+				if (this.isSending) return;
+				this.isSending = true;
+				setTimeout(() => {
+					this.isSending = false;
+				}, 800); // 800ms 内禁止再次发送
+
+				const text = (this.value || '').trim();
+				if (!text) {
+					uni.showToast({
+						title: "不能发送空消息",
+						icon: 'none'
+					});
+					return;
+				}
+				if (!this.isSocketAvailable()) {
+					if (retries > 0) {
+						uni.showToast({
+							title: `连接不稳定,正在重试(${retries}次)...`,
+							icon: 'none'
+						});
+						// 延迟500ms重试,重试次数减1
+						setTimeout(() => this.sendMsg(retries - 1), 500);
+					} else {
+						uni.showToast({
+							title: '连接已断开,发送失败',
+							icon: 'none'
+						});
+						this.value = text; // 恢复输入框内容
+					}
+					return;
+				}
+				const liveId = this.liveId;
+				this.value = ''; // 立即清空输入框
+				// 构造发送给服务端的消息数据
+				const data = {
+					liveId,
+					userId: this.userData.userId,
+					userType: 0,
+					cmd: "sendMsg",
+					msg: text,
+					nickName: this.userData.nickname || '未命名',
+					avatar: this.userData.avatar || '/static/images/avatar.png'
+				};
+				// 发送socket消息
+				try {
+					this.socket.send({
+						data: JSON.stringify(data),
+						success: () => {
+							this.value = '';
+						},
+						fail: (err) => {
+							console.error("消息发送失败:", err);
+							if (retries > 0) {
+								uni.showToast({
+									title: `发送失败,正在重试(${retries}次)`,
+									icon: 'none'
+								});
+								setTimeout(() => this.sendMsg(retries - 1), 500);
+							} else {
+								uni.showToast({
+									title: '发送失败,请稍后再试',
+									icon: 'none'
+								});
+								this.value = text; // 恢复输入框内容
+							}
+						}
+					});
+				} catch (err) {
+					console.error("发送消息异常:", err);
+					if (retries > 0) {
+						setTimeout(() => this.sendMsg(retries - 1), 500);
+					} else {
+						uni.showToast({
+							title: '发送失败,请稍后再试',
+							icon: 'none'
+						});
+						this.value = text;
+					}
+				}
+			}
+
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	.skeleton-item {
+		display: flex;
+		padding: 20rpx;
+		background: #fff;
+		margin-bottom: 16rpx;
+		border-radius: 16rpx;
+	}
+
+	.skeleton-img {
+		width: 200rpx;
+		height: 200rpx;
+		background: #f0f0f0;
+		border-radius: 8rpx;
+		margin-right: 24rpx;
+		animation: pulse 1.5s ease-in-out infinite;
+	}
+
+	.skeleton-content {
+		flex: 1;
+	}
+
+	.skeleton-line {
+		height: 20rpx;
+		background: #f0f0f0;
+		margin-bottom: 16rpx;
+		border-radius: 4rpx;
+		animation: pulse 1.5s ease-in-out infinite;
+	}
+
+	.skeleton-line.short {
+		width: 60%;
+	}
+
+	.skeleton-line.medium {
+		width: 80%;
+	}
+
+	.skeleton-line.long {
+		width: 95%;
+	}
+
+	@keyframes pulse {
+		0% {
+			opacity: 1;
+		}
+
+		50% {
+			opacity: 0.5;
+		}
+
+		100% {
+			opacity: 1;
+		}
+	}
+
+
+
+
+
+
+
+	::v-deep .u-icon--right {
+		justify-content: flex-end !important;
+	}
+
+	// 无头像用户文字样式
+	.text-white {
+		color: #ffffff;
+	}
+
+	.text-xs {
+		font-size: 18rpx;
+	}
+
+	.text-sm {
+		font-size: 24rpx;
+	}
+
+	.w52,
+	.w72 {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.swiper-wrapper {
+		position: relative;
+		width: 100%;
+		height: 100vh;
+		overflow: hidden;
+		background-color: #000000;
+
+		.container {
+			width: 100%;
+			height: 100%;
+			position: relative;
+			transition: opacity 0.3s ease;
+			transform: translateZ(0);
+			will-change: opacity;
+		}
+	}
+
+	.welcome-message {
+		position: fixed;
+		width: 100%;
+		bottom: 38vh;
+		left: 50%;
+		transform: translateX(-50%);
+		color: white;
+		padding: 10px 20px;
+		border-radius: 20px;
+		z-index: 10;
+		transition: opacity 0.3s ease;
+	}
+
+	.send {
+		background-color: #fafafa;
+		border-radius: 28rpx;
+		padding: 14rpx 16rpx;
+		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 {
+		will-change: transform; // 提示浏览器优化
+		contain: layout style paint; // 限制渲染范围
+
+
+		max-width: 100%;
+		border-radius: 30rpx;
+		background-color: rgba(33, 33, 33, 0.5);
+		padding: 10rpx 30rpx;
+	}
+
+	.content {
+		position: relative;
+		z-index: 2;
+		height: 100%;
+		width: 100%;
+		top: 0;
+		left: 0;
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+
+		.activity-box {
+			position: fixed;
+			top: 188rpx;
+			left: 30rpx;
+			z-index: 999999;
+			display: flex;
+			align-items: center;
+
+			.item-box {
+				-webkit-transform: translateZ(0);
+				/* 硬件加速 */
+				transform: translateZ(0);
+				border-radius: 16rpx;
+				background-color: rgba(77, 77, 77, 0.5);
+				width: 90rpx;
+				height: 100rpx;
+				margin-right: 20rpx;
+				position: relative;
+				z-index: 999;
+
+				.tip {
+					position: absolute;
+					width: 100%;
+					bottom: 0;
+					color: #fafcff;
+					font-size: 26rpx;
+					background-color: rgba(15, 15, 15, 0.8);
+					border-radius: 16rpx;
+					text-align: center;
+				}
+
+				.item {
+					margin: 0 auto;
+					padding: 10rpx 0;
+
+					.img {
+						height: 100%;
+					}
+				}
+			}
+		}
+
+		// 减少重绘
+		.side-group,
+		.content-top {
+			will-change: transform;
+		}
+
+		.side-group {
+			position: absolute;
+			top: 65%;
+			right: 30rpx;
+			z-index: 1000;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+
+			.side-item {
+				font-weight: 500;
+				font-size: 24rpx;
+				color: #FFFFFF;
+				margin-bottom: 32rpx;
+				text-align: center;
+
+				// 将 button 选择器改为类选择器
+				.button-reset::after {
+					border: none !important;
+					padding: 0 !important;
+					margin: 0 !important;
+				}
+
+				.button-reset {
+					background-color: transparent !important;
+					padding: 0 !important;
+					line-height: inherit !important;
+					margin: 0 !important;
+					width: auto !important;
+					font-weight: 500 !important;
+					border-radius: none !important;
+				}
+
+				.image {
+					width: 72rpx;
+					height: 72rpx;
+				}
+			}
+		}
+
+		.content-top {
+			width: 100%;
+			margin-top: 48rpx;
+			display: flex;
+			justify-content: space-between;
+			padding: 0 24rpx;
+			box-sizing: border-box;
+
+
+
+			.sum {
+				width: 80rpx;
+				height: 52rpx;
+				background: rgba(0, 0, 0, 0.5);
+				border-radius: 26rpx 26rpx 26rpx 26rpx;
+				font-size: 24rpx;
+				color: #FFFFFF;
+				text-align: center;
+				line-height: 52rpx;
+
+			}
+		}
+
+		.follow-btn {
+			padding: 8rpx 16rpx;
+			background: linear-gradient(270deg, #FF5C03 0%, #FFAC64 100%);
+			border-radius: 26rpx;
+			font-weight: 500;
+			font-size: 26rpx;
+			color: #FFFFFF;
+		}
+	}
+
+	.trailer-box {
+		position: relative;
+		top: 15%;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		color: #ffffff;
+		padding: 20rpx;
+
+		.button {
+			margin-top: 20rpx;
+			background: #6d7bd4;
+			color: #fff;
+			border-radius: 20rpx;
+			padding: 20rpx 30rpx;
+			position: relative;
+			z-index: 99999;
+		}
+
+		.ash {
+			background: #636363;
+		}
+
+		.countdown-item {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+
+			.white {
+				width: 60rpx;
+				height: 60rpx;
+				text-align: center;
+				overflow: hidden;
+				background: #FFFFFF;
+				border-radius: 8rpx;
+				margin: 30rpx 10rpx 0;
+				font-weight: 600;
+				font-size: 24rpx;
+				color: #000000;
+				line-height: 60rpx;
+			}
+		}
+
+		.item {
+			width: 100%;
+			height: 400rpx;
+		}
+
+		.name {
+
+			font-size: 34rpx;
+		}
+
+		.img {
+			margin-bottom: 40rpx;
+			width: 240rpx;
+			height: 240rpx;
+		}
+
+		.title {
+			margin-top: 30rpx;
+			font-size: 42rpx;
+			font-weight: 500;
+		}
+
+	}
+
+
+	.videolist {
+		position: relative;
+		height: 100vh;
+		width: 100%;
+
+		.video {
+			transform: translateZ(0);
+			backface-visibility: hidden;
+			perspective: 1000;
+
+
+			height: 100vh;
+			width: 100%;
+			// background-color: rgba(57, 57, 57, 0.4);
+
+			.item {
+				width: 100%;
+				height: 100%;
+			}
+
+			.time {
+
+				color: #ffffff;
+				font-size: 20rpx;
+				margin-left: 10rpx;
+			}
+
+			.end {
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+				font-size: 36rpx;
+				color: #fff;
+			}
+
+			.lable {
+				position: absolute;
+				top: 50rpx;
+				right: 16rpx;
+				background-color: rgba(57, 57, 57, 0.6);
+				padding: 4rpx 10rpx;
+				color: #fff;
+				border-radius: 15rpx;
+			}
+		}
+
+		.video_row {
+			position: absolute;
+			top: 20%;
+			max-height: 450rpx;
+			z-index: 99;
+		}
+	}
+
+	.prize-card {
+		width: 504rpx;
+		padding: 40rpx 40rpx 30rpx;
+		box-sizing: border-box;
+		display: flex;
+		flex-direction: column;
+		border-radius: 20rpx;
+		align-items: center;
+		background: linear-gradient(180deg, #f7823f 0%, #ffd4be 27%, #ffffff 100%);
+		position: relative;
+
+		.nav-img {
+			width: 311rpx;
+			position: absolute;
+			top: -122rpx;
+			left: 50%;
+			transform: translateX(-50%);
+
+		}
+
+		.title {
+			color: #C32008;
+			font-size: 34rpx;
+			font-weight: 600;
+			margin: 20rpx 0 40rpx;
+		}
+
+		.prize-content {
+			width: 100%;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			font-size: 28rpx;
+			margin: 10rpx 0;
+
+			.txt {
+				font-weight: 600;
+			}
+		}
+
+		.tip {
+			font-size: 28rpx;
+			color: #414141;
+			margin: 40rpx 0;
+		}
+
+		.button {
+			width: 200rpx;
+			height: 70rpx;
+			line-height: 70rpx;
+			background: linear-gradient(180deg, #ff7c30 0%, #FF3A1E 100%);
+			border-radius: 28rpx;
+			font-weight: 500;
+			font-size: 32rpx;
+			color: #ffffff;
+			text-align: center;
+		}
+	}
+
+	.no-prize-card {
+		width: 504rpx;
+		padding: 40rpx 40rpx 30rpx;
+		box-sizing: border-box;
+		display: flex;
+		flex-direction: column;
+		border-radius: 20rpx;
+		align-items: center;
+		position: relative;
+
+		.img {
+			margin-top: 40rpx;
+			width: 300rpx;
+			height: 300rpx;
+		}
+
+		.tip {
+			font-size: 36rpx;
+			color: #414141;
+			margin: 40rpx 0;
+		}
+
+		.button {
+			width: 220rpx;
+			height: 80rpx;
+			line-height: 80rpx;
+			background: linear-gradient(180deg, #fdfbb8 0%, #b79243 100%);
+			border-radius: 28rpx;
+			font-weight: 500;
+			font-size: 32rpx;
+			color: #ffffff;
+			text-align: center;
+		}
+	}
+
+	.red-card {
+		width: 550rpx;
+		height: 636rpx;
+		position: relative;
+
+		.img {
+			position: absolute;
+			width: 100%;
+			height: 100%;
+		}
+
+		.red-content {
+			position: relative;
+			z-index: 5;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+
+			.title {
+				font-size: 36rpx;
+				color: #FF3A1E;
+				margin: 180rpx 0 90rpx;
+			}
+
+			.txt {
+				font-size: 28rpx;
+				color: #FFECC3;
+				margin: 80rpx 0 40rpx;
+			}
+
+			.button {
+				width: 392rpx;
+				height: 96rpx;
+				line-height: 96rpx;
+				background: linear-gradient(180deg, #FFF4D5 0%, #FFE5B1 100%);
+				border-radius: 48rpx 48rpx 48rpx 48rpx;
+				font-weight: 600;
+				font-size: 36rpx;
+				color: #C32008;
+				text-align: center;
+			}
+		}
+
+	}
+
+	.integral-box {
+		min-width: 400rpx;
+		max-width: 600rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		border-radius: 20rpx;
+		overflow: hidden;
+
+		.top {
+			width: 100%;
+			position: relative;
+
+			.title {
+				width: 100%;
+				font-weight: 600;
+				font-size: 40rpx;
+				color: #FFFFFF;
+				text-shadow: 0px 4px 8px rgba(255, 89, 2, 0.8);
+				position: absolute;
+				top: 50rpx;
+				text-align: center;
+			}
+
+			.photo {
+				width: 100%;
+
+			}
+		}
+
+		.item {
+			padding: 20rpx;
+
+			.title {
+				font-weight: 500;
+				font-size: 32rpx;
+				text-align: center;
+			}
+
+			.button {
+				font-size: 32rpx;
+				margin-top: 20rpx;
+				background: linear-gradient(270deg, #ff4702 0%, #fe6304 100%);
+				color: #fff;
+				text-align: center;
+				padding: 18rpx 60rpx;
+				border-radius: 10rpx;
+				font-weight: 500;
+			}
+		}
+	}
+
+	.goods {
+		position: fixed;
+		bottom: 140rpx;
+		right: 104rpx;
+		z-index: 5;
+		background-color: #fff;
+		border-radius: 20rpx;
+		overflow: hidden;
+		width: 280rpx;
+		padding: 4rpx;
+
+		.top {
+			position: absolute;
+			top: 4rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			color: #fff;
+			width: 100%;
+			padding-right: 10rpx;
+			box-sizing: border-box;
+
+			.left {
+				background-color: rgba(0, 0, 0, 0.8);
+				padding: 12rpx;
+				font-size: 22rpx;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				border-radius: 10rpx;
+			}
+		}
+
+		.photo {
+			width: 100%;
+			height: 180rpx;
+			border-radius: 16rpx 16rpx 0 0;
+			overflow: hidden;
+		}
+
+		.item {
+			padding: 4rpx;
+
+			.price {
+				font-size: 30rpx;
+
+				.red {
+					color: #FF5701;
+					font-weight: 600;
+					margin-right: 10rpx;
+				}
+
+				.del {
+					color: #828282;
+					font-weight: 500;
+					font-size: 28rpx;
+					text-decoration: line-through
+				}
+			}
+
+			.title {
+				font-weight: 500;
+				font-size: 30rpx;
+				margin: 10rpx 0 12rpx;
+			}
+
+			.button {
+				background: linear-gradient(270deg, #ff4702 0%, #fe6304 100%);
+				color: #fff;
+				text-align: center;
+				padding: 16rpx 0;
+				border-radius: 10rpx;
+				font-weight: 500;
+				font-size: 30rpx;
+			}
+		}
+	}
+
+	.coupon-pop {
+		position: fixed;
+		bottom: 140rpx;
+		right: 100rpx;
+		z-index: 5;
+		border-radius: 20rpx;
+		width: 320rpx;
+
+		.coupon-block {
+			width: 100%;
+			position: relative;
+
+			.item {
+				width: 100%;
+				position: absolute;
+				top: 20rpx;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				color: #fff;
+
+				.title {
+					font-weight: 500;
+					font-size: 30rpx;
+					margin: 16rpx 0 12rpx;
+				}
+
+				.price {
+					font-size: 40rpx;
+
+					.bold {
+						font-size: 56rpx;
+						font-weight: 600;
+					}
+				}
+
+				.txt {
+					font-weight: 500;
+					font-size: 30rpx;
+					margin: 5rpx 0;
+				}
+
+				.button {
+					background: linear-gradient(270deg, #fffce1 0%, #ffeaaf 100%);
+					color: #ff0004;
+					text-align: center;
+					padding: 16rpx 0;
+					border-radius: 40rpx;
+					font-weight: 500;
+					font-size: 30rpx;
+					width: 70%;
+					margin-top: 26rpx;
+				}
+			}
+
+			.bg {
+				height: 432rpx;
+				width: 100%;
+			}
+
+			.nav {
+				position: absolute;
+				height: 120rpx;
+				top: -120rpx;
+				left: 0;
+				width: 100%;
+				z-index: 6;
+			}
+
+			.close {
+				position: absolute;
+				right: 10rpx;
+				top: 10rpx;
+			}
+		}
+	}
+
+	.icon-bg {
+		background-color: rgba(57, 57, 57, 0.8);
+		border-radius: 50%;
+		width: 88rpx;
+		height: 88rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		transition: transform 0.2s ease;
+	}
+
+	.list {
+		width: 80%;
+		margin-bottom: 20rpx;
+		animation: simpleFade .2s;
+	}
+
+	@keyframes simpleFade {
+		from {opacity: 0;}
+		to {opacity: 1;}
+	}
+
+	.shop-prompt {
+		position: absolute;
+		bottom: 750rpx;
+		left: 24rpx;
+		padding: 6rpx 20rpx;
+		background: rgba(230, 154, 34, 0.7);
+		border-radius: 24rpx;
+		z-index: 9;
+		font-weight: 500;
+		color: #FFFFFF;
+		transition: opacity 0.3s ease;
+	}
+
+
+	.view-box {
+		position: relative;
+		height: 40vh;
+		/* 设置弹出层高度为视窗高度的70% */
+		padding: 40rpx 0rpx;
+		box-sizing: border-box;
+		display: flex;
+		flex-direction: column;
+
+		.scroll-content {
+			flex: 1;
+			margin-top: 50rpx;
+			overflow-y: auto;
+			padding: 0 40rpx;
+		}
+
+		.bottom {
+			padding: 20rpx 40rpx;
+			position: absolute;
+			bottom: 0;
+			width: 100%;
+			box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(195, 195, 195, 0.3);
+			background: #fff;
+		}
+	}
+
+	// 抽奖
+	.prize-box {
+		position: relative;
+
+		.nav-img {
+			width: 311rpx;
+			position: absolute;
+			top: -122rpx;
+			left: 50%;
+			transform: translateX(-50%);
+		}
+
+		.bg-img {
+			position: absolute;
+			top: 0;
+			left: 0;
+			width: 100%;
+			height: 100%;
+			z-index: 1;
+		}
+
+		.prize-content {
+			position: relative;
+			z-index: 2;
+			padding: 24rpx 0 68rpx;
+
+			.item {
+				flex: 1;
+				text-align: center;
+
+			}
+
+			.white-item {
+				width: 40rpx;
+				height: 40rpx;
+				text-align: center;
+				overflow: hidden;
+				background: #FFFFFF;
+				box-shadow: inset 0rpx 2rpx 8rpx 0rpx #FFEBB2;
+				border-radius: 8rpx;
+				margin: 4rpx;
+				font-weight: 600;
+				font-size: 24rpx;
+				color: #F85D22;
+				line-height: 40rpx;
+			}
+
+			.item-group {
+				width: 100%;
+			}
+
+			.point-group {
+				margin: 20rpx 0 50rpx;
+				display: flex;
+				gap: 6rpx;
+
+				.item {
+					width: 20rpx;
+					height: 8rpx;
+					background: rgba(255, 255, 255, 0.5);
+					border-radius: 4rpx 4rpx 4rpx 4rpx;
+				}
+
+				.selected {
+					background: #FFEB66;
+				}
+			}
+
+			.button {
+				margin-top: 30rpx;
+				width: 520rpx;
+				height: 88rpx;
+				line-height: 88rpx;
+				background: linear-gradient(180deg, #FFF4D6 0%, #FFEB66 100%);
+				box-shadow: 0rpx 10rpx 8rpx 4rpx rgba(246, 82, 25, 0.5);
+				border-radius: 44rpx;
+				font-weight: 500;
+				font-size: 36rpx;
+				color: #F4410B;
+				text-align: center;
+			}
+		}
+	}
+
+	.more-block {
+		border-radius: 20rpx 0 0 20rpx;
+		padding: 70rpx 30rpx;
+		display: flex;
+		justify-content: space-between;
+
+		.item {
+			text-align: center;
+		}
+	}
+
+	.winning_record {
+		position: relative;
+		height: 800rpx;
+
+		.head_bg {
+			position: absolute;
+			top: -125rpx;
+			left: 50%;
+			width: 311rpx;
+			transform: translateX(-50%);
+		}
+
+		.bg {
+			width: 100%;
+			height: 100%;
+		}
+
+		.winning_content {
+			position: absolute;
+			top: 50rpx;
+			color: #fff;
+			width: 100%;
+			padding: 0 36rpx;
+			box-sizing: border-box;
+
+			.title {
+				text-align: center;
+				font-size: 40rpx;
+				font-weight: 500;
+				margin-bottom: 40rpx;
+			}
+
+			.row {
+				display: flex;
+				justify-content: space-between;
+
+				.head {
+					flex: 1;
+					text-align: center;
+				}
+
+				.start {
+					flex: 1;
+				}
+
+				.end {
+					flex: 1;
+					text-align: end;
+				}
+			}
+		}
+	}
+
+	.shoppop {
+		padding: 22rpx 16rpx;
+
+		.shoppop-top {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 0 16rpx 22rpx;
+
+			.search-input {
+				width: 414rpx;
+				height: 76rpx;
+				background: #FFFFFF;
+				border-radius: 36rpx;
+				margin-left: 20rpx;
+				padding: 0 32rpx;
+				box-sizing: border-box;
+				font-size: 24rpx;
+				margin-right: 24rpx;
+
+			}
+
+			.search-top {
+				font-size: 20rpx;
+				color: #222222;
+			}
+		}
+
+
+		.shop-list {
+			overflow: hidden;
+
+			.list-item {
+				display: flex;
+				align-items: center;
+				padding: 20rpx 16rpx;
+				background: #FFFFFF;
+				border-radius: 16rpx;
+				margin-bottom: 16rpx;
+
+				.goods-img {
+					width: 200rpx;
+					height: 200rpx;
+					border-radius: 16rpx;
+					overflow: hidden;
+					position: relative;
+					margin-right: 24rpx;
+
+					.img {
+						width: 100%;
+						height: 100%;
+					}
+
+					.goods-label {
+						position: absolute;
+						top: 0;
+						width: 64rpx;
+						height: 40rpx;
+						background: rgba(0, 0, 0, 0.5);
+						border-radius: 16rpx 0rpx 16rpx 0rpx;
+						text-align: center;
+						font-weight: 500;
+						font-size: 28rpx;
+						color: #FFFFFF;
+					}
+				}
+
+				.goods-right {
+					flex: 1;
+
+					.goods-title {
+						font-weight: 500;
+						font-size: 30rpx;
+						color: #000000;
+						margin-bottom: 10rpx;
+					}
+
+					.goods-details {
+						font-size: 24rpx;
+						color: #999999;
+						margin: 10rpx 0 20rpx;
+					}
+
+					.goods-people {
+						font-size: 22rpx;
+						color: #E69A22;
+						height: 56rpx;
+					}
+
+					.goods-shop {
+						display: flex;
+						justify-content: space-between;
+
+						.nummber {
+							color: #FF5C03;
+							font-size: 22rpx;
+							font-weight: 500;
+						}
+
+						.btn-group {
+							text-align: center;
+							line-height: 56rpx;
+
+							.collect-btn {
+								width: 72rpx;
+								height: 100%;
+								background: #F5F7FA;
+								border-radius: 8rpx 0rpx 0rpx 8rpx;
+
+							}
+
+							.shop-btn {
+								width: 152rpx;
+								background: linear-gradient(270deg, #FF5C03 0%, #FFAC64 100%);
+								border-radius: 0rpx 8rpx 8rpx 0rpx;
+								font-weight: 500;
+								font-size: 30rpx;
+								color: #FFFFFF;
+
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 1 - 1
pages_course/livingList.vue

@@ -4,7 +4,7 @@
 			:down="downOption" :up="upOption">
 			:down="downOption" :up="upOption">
 			<view class="list">
 			<view class="list">
 				<view class="list-item" @click="goLive(item)" v-for="(item,index) in list" :key="index">
 				<view class="list-item" @click="goLive(item)" v-for="(item,index) in list" :key="index">
-					<image class="img" v-if="item.liveImgUrl" :src="item.liveImgUrl"></image>
+					<image class="img" mode="aspectFill"  v-if="item.liveImgUrl" :src="item.liveImgUrl"></image>
 					<view class="info">
 					<view class="info">
 						<text>{{item.liveName}}</text>
 						<text>{{item.liveName}}</text>
 					</view>
 					</view>

+ 3 - 5
pages_shopping/live/goods.vue

@@ -15,7 +15,7 @@
 				<view class="num-box">{{ activeBanner }}/{{ banner.length }}</view>
 				<view class="num-box">{{ activeBanner }}/{{ banner.length }}</view>
 			</view>
 			</view>
 			<!-- 详细信息 -->
 			<!-- 详细信息 -->
-			<view class="det-info">
+			<view class="det-info" v-if="!!goosDetail">
 				<view class="price-box">
 				<view class="price-box">
 					<view class="price">
 					<view class="price">
 						<text class="label">会员价</text>
 						<text class="label">会员价</text>
@@ -90,9 +90,7 @@
 </template>
 </template>
 
 
 <script>
 <script>
-	import {
-		liveGoodsDetail
-	} from '@/api/living'
+	import {liveGoodsDetail} from '@/api/living'
 	import {
 	import {
 		liveOrderKey, // 生成订单key
 		liveOrderKey, // 生成订单key
 	} from "@/api/order.js"
 	} from "@/api/order.js"
@@ -113,7 +111,7 @@
 				storeId: null,
 				storeId: null,
 				serviceList: ['品质保障', '药师服务', '隐私保护'],
 				serviceList: ['品质保障', '药师服务', '隐私保护'],
 				productId: null,
 				productId: null,
-				goosDetail: {}, //商品详情
+				goosDetail: null, //商品详情
 				buyText: "立即购买",
 				buyText: "立即购买",
 				goodsNum: 0, //商品选择数量
 				goodsNum: 0, //商品选择数量
 				// 当前轮播的图片
 				// 当前轮播的图片

+ 22 - 0
static/svg/weixin36.svg

@@ -0,0 +1,22 @@
+<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="weixin_icon36" clip-path="url(#clip0_356_1034)">
+<g id="Vector" filter="url(#filter0_d_356_1034)">
+<path d="M23.66 14.0748C24.028 14.0748 24.39 14.107 24.754 14.153C23.774 8.90104 18.896 5 13.326 5C7.1 5 2 9.88147 2 16.084C2 19.6628 3.696 22.6018 6.532 24.8849L5.4 28.8044L9.36 26.5213C10.776 26.8412 11.912 27.1726 13.326 27.1726C13.682 27.1726 14.034 27.1542 14.382 27.1243C14.162 26.252 14.032 25.3406 14.032 24.3901C14.034 18.6962 18.282 14.0748 23.66 14.0748ZM17.572 10.542C18.428 10.542 18.99 11.1887 18.99 12.1692C18.99 13.145 18.428 13.7986 17.572 13.7986C16.726 13.7986 15.874 13.145 15.874 12.1692C15.874 11.1864 16.724 10.542 17.572 10.542ZM9.646 13.7986C8.796 13.7986 7.94 13.145 7.94 12.1692C7.94 11.1887 8.796 10.542 9.646 10.542C10.496 10.542 11.06 11.1864 11.06 12.1692C11.06 13.145 10.496 13.7986 9.646 13.7986ZM34 24.2336C34 19.023 29.468 14.7768 24.378 14.7768C18.988 14.7768 14.746 19.0253 14.746 24.2336C14.746 29.458 18.99 33.6904 24.378 33.6904C25.506 33.6904 26.644 33.3659 27.776 33.0391L30.882 35L30.03 31.7411C32.304 29.7756 34 27.1726 34 24.2336ZM21.254 22.6018C20.692 22.6018 20.122 21.9574 20.122 21.2992C20.122 20.6502 20.692 19.9965 21.254 19.9965C22.114 19.9965 22.672 20.6502 22.672 21.2992C22.672 21.9574 22.114 22.6018 21.254 22.6018ZM27.484 22.6018C26.926 22.6018 26.358 21.9574 26.358 21.2992C26.358 20.6502 26.924 19.9965 27.484 19.9965C28.336 19.9965 28.902 20.6502 28.902 21.2992C28.902 21.9574 28.336 22.6018 27.484 22.6018Z" fill="white"/>
+</g>
+</g>
+<defs>
+<filter id="filter0_d_356_1034" x="0" y="5" width="36" height="34" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="2"/>
+<feGaussianBlur stdDeviation="1"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_356_1034"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_356_1034" result="shape"/>
+</filter>
+<clipPath id="clip0_356_1034">
+<rect width="36" height="36" fill="white"/>
+</clipPath>
+</defs>
+</svg>

部分文件因文件數量過多而無法顯示