liujiaxin 2 nedēļas atpakaļ
vecāks
revīzija
06e45349e7

+ 10 - 0
api/live.js

@@ -23,6 +23,8 @@ const api = {
 	liveOrderUser: (liveId) => `/app/live/liveOrder/liveOrderUser/${liveId}`, // 正在购买
 	showGoods: (liveId) => `/app/live/liveGoods/showGoods/${liveId}`, // 弹出商品卡片
 	currentActivities: (liveId) => `/app/live/currentActivities?liveId=${liveId}`, // 弹出商品卡片
+	claim: '/app/live/liveLottery/claim', // 抽奖
+	liveLottery: '/app/live/liveLottery/detail', // 抽奖查询
 }
 // 点赞
 export function liveDataLike(liveId, data = {}) {
@@ -124,4 +126,12 @@ export function currentActivities(liveId, data = {}) {
 	return request(api.currentActivities(liveId), data, 'GET', 'application/json;charset=UTF-8',false)
 }
 
+//抽奖
+export function claim(data) {
+	return request(api.claim, data, 'POST', 'application/json;charset=UTF-8',false)
+}
+// 抽奖查询
+export function liveLottery(data) {
+	return request(api.liveLottery, data, 'POST', 'application/json;charset=UTF-8',false)
+}
 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 306 - 538
pages/home/living.vue


+ 2603 - 0
pages/home/living3.vue

@@ -0,0 +1,2603 @@
+<template>
+	<view class="swiper-wrapper">
+		<swiper class="swiper-container" :current="currentSwiperIndex" :circular="false" vertical
+			@change="onSwiperChange" :style="{height: '100vh'}" :duration="swiperDuration" :lazy-load="true"
+			:display-multiple-items="1">
+			<swiper-item v-for="(liveItem, index) in list" :key="liveItem.liveId">
+				<view class="container" :class="{active: currentSwiperIndex === index}">
+					<view class="blackbg"></view>
+					<view class="content">
+						<!-- 页面内容 -->
+						<view style="position: fixed;top: 0;z-index: 5;" class="content-top">
+							<view class="u-flex-y-center">
+								<image @click="goBack" class="w60 h64 mr26" src="/static/images/live/return.png">
+								</image>
+								<view class="align-center"
+									style="padding: 6rpx 4rpx;height: 64rpx;background: rgba(0,0,0,0.5);border-radius: 32rpx;">
+									<u-avatar :src="liveItem.liveImgUrl||$img.logo" size="32"></u-avatar>
+									<view class="colorf ml10 mr6">
+										<view>{{liveItem.liveName?truncateString(liveItem.liveName,8):"未命名"}}</view>
+									</view>
+								</view>
+							</view>
+							<view class="u-flex-end align-center" @click="toggleViewerList" style="margin-top: 100rpx;">
+								<image v-if="Array.isArray(filteredViewers)" class="w52 h52 mr4"
+									v-for="(item,viewerIndex) in filteredViewers" :key="viewerIndex"
+									style="border-radius: 26rpx;" :src="item.avatar||$img.logo">
+								</image>
+								<view class="sum">{{liveUserTotal||0}}</view>
+							</view>
+
+						</view>
+						<!-- 右边的 -->
+						<view :class=" liveItem.showType==1 ? 'siderow-group' : 'side-group'">
+							<view class="side-item">
+								<image class="image" @click="onLike(liveItem)" src="/static/images/like.png">
+								</image>
+								<view>{{liveItem.liveViewData?.like||0}}</view>
+							</view>
+							<!-- <view class="side-item">
+								<image @click="goStore(liveItem)" src="/static/images/live/shop.png"></image>
+								<view>店铺</view>
+							</view> -->
+							<view class="side-item">
+								<button open-type="share" class="button">
+									<image class="image" src="/static/images/share.png" mode="widthFix"></image>
+								</button>
+								<view>分享</view>
+							</view>
+						</view>
+						<!-- 红包内容 -->
+						<view class="activity-box">
+							<!-- v-if="liveItem.redInfo?.redStatus==1&&isShowRed" -->
+							<view class="item-box">
+								<view class="u-flex-y-center">
+									<view class="tip">领红包</view>
+									<view class="item">
+										<image class="w70" @click="onRed(liveItem)" src="/static/images/redbag.png"
+											mode="widthFix">
+										</image>
+									</view>
+								</view>
+							</view>
+							<!-- v-if="liveItem.redInfo?.lotteryStatus==1&&isShowLottery" -->
+							<view class="item-box">
+								<view class="u-flex-y-center">
+									<view class="tip">抽奖</view>
+									<view class="item">
+										<image class="w60" @click="onLottery(liveItem)" src="/static/images/lottery.png"
+											mode="widthFix">
+										</image>
+									</view>
+								</view>
+							</view>
+						</view>
+						<view class="shop-prompt f30 u-flex-y-center" v-if="showPurchasePrompt&&orderUser?.count">
+							<image class="w32 h32 mr8" src="/static/images/live/shopping.png"></image>
+							<text> {{orderUser.userName ? maskString(orderUser.userName) : ''}} 等
+								{{orderUser.count || 0}}
+								人正在去购买</text>
+						</view>
+
+						<view class="videolist" style="margin: auto 0">
+							<view class="video" style="height:100vh">
+								<!-- 视频组件 -->
+								<live-player v-if="currentSwiperIndex === index  && liveItem.liveType === 1"
+									:id="'myLivePlayer_' + liveItem.liveId"
+									:class="liveItem.showType == 1 ? 'video_row' : 'videotop'" :src="liveItem.livingUrl"
+									autoplay mode="live" object-fit="contain" :waiting="false" :muted="false"
+									:orientation="liveItem.showType == 1 ? 'horizontal' : 'vertical'"
+									@statechange="onLiveStateChange($event, liveItem)"
+									@error="onLiveError($event, liveItem)" class="live-player"></live-player>
+
+
+								<!-- 	<video v-if="currentSwiperIndex === index && liveItem.livingUrl"
+									:id="'myVideo_' + liveItem.liveId"
+									:class="liveItem.showType == 1 ? 'video_row' : 'videotop'" :src="liveItem.livingUrl"
+									:controls='false' object-fit='contain' :custom-cache="false"
+									:enable-progress-gesture="false" vslide-gesture-in-fullscreen='true'
+									:show-center-play-btn="false" :http-cache="false" @error="videoError">
+								</video> -->
+
+								<video v-if="currentSwiperIndex === index && liveItem.liveType === 2"
+									:class="liveItem.showType == 1 ? 'video_row' : 'videotop'" :src="liveItem.videoUrl"
+									:autoplay="currentSwiperIndex === index" :controls='false' object-fit='contain'
+									:custom-cache="false" :enable-progress-gesture="false"
+									vslide-gesture-in-fullscreen='true' :show-center-play-btn="false"
+									:http-cache="false" loop @error="videoError">
+								</video>
+								<view v-if="liveItem.videoUrl" class="time">{{liveItem.totalTime}}</view>
+							</view>
+						</view>
+
+						<!-- 底部聊天区域 -->
+						<view class="pb40 mt90" style="position: fixed;bottom: 120rpx;width: 100%;">
+							<view class="w100 h300 mt20">
+								<scroll-view enable-flex scroll-y="true" class="talk p20 scrolly flex-1 column"
+									style="width: calc(100% - 40rpx);height: calc(100% - 40rpx);"
+									:scroll-into-view="liveItem.scrollIntoView">
+									<view>
+										<view class="list justify-start" v-for="(item,talkIndex) in liveItem.talklist"
+											:key="talkIndex" v-show="item.cmd=='announcement'">
+											<view class="talk-list ml16 justify-start">
+												<view class="fs30">
+													<text class='colorf'>
+														{{item.msg}}直播间{{liveItem.messageContent}}</text>
+												</view>
+											</view>
+										</view>
+									</view>
+
+									<view class="list justify-start" v-for="(item,talkIndex) in liveItem.talklist"
+										:key="talkIndex" :id="`list_${talkIndex}`"
+										v-show="item.cmd!='red'&&item.cmd!='out'&&item.cmd!='entry'">
+										<view class="talk-list ml16 justify-start">
+											<view class="fs30">
+												<text style="color: #FFDA73;">{{item.nickName}}:</text>
+												<text class='colorf'>{{item.msg}}</text>
+											</view>
+										</view>
+									</view>
+									<view v-if="liveItem.showWelcomeMessage" class="welcome-message">
+										<view class="list justify-start" v-for="(item,talkIndex) in liveItem.talklist"
+											:key="talkIndex" v-show="item.cmd=='entry'||item.cmd=='out'">
+											<view class="talk-list ml16 justify-start">
+												<view class="fs30">
+													<text style="color: #ff89d6;">{{item.nickName}} </text>
+													<text class='colorf'>
+														{{item.msg}}直播间{{liveItem.messageContent}}</text>
+												</view>
+											</view>
+										</view>
+									</view>
+								</scroll-view>
+							</view>
+
+							<!-- 底部输入框和操作按钮 -->
+							<view class="justify-between p24 input-box">
+								<view class="u-flex-y-center w580"
+									style="background:rgba(57, 57, 57, 1);padding:10rpx 14rpx 10rpx 32rpx;box-sizing:border-box;border-radius:36rpx;">
+									<u-input :placeholder="liveItem.placeholderText" border="none"
+										customStyle='font-size:24rpx;' v-model="liveItem.value" shape='circle'
+										color='#fff' placeholderStyle='color:#e7e7e7' class="ml20">
+									</u-input>
+									<view class="send" @click="sendMsg(liveItem)">发送</view>
+								</view>
+								<view class="justify-between mr15 align-center">
+									<view class="icon-bg ml20" @click="openCart(liveItem)">
+										<image src="/static/images/shopping.png" class="w58 h58"></image>
+									</view>
+								</view>
+							</view>
+						</view>
+					</view>
+					<u-popup :show="liveItem.goodsCard?.isShow" @close="!liveItem.goodsCard?.isShow" round='20rpx'
+						mode="center" bgColor='#ffffff'>
+						<view class="goods">
+							<view class="top">
+								<view class="left">
+									<image class="w30 h30 mr8" src="/static/images/signal.png"></image>讲解中
+								</view>
+								<image class="w30 h30" src="/static/images/close.png"
+									@click="liveItem.goodsCard.isShow=false"></image>
+							</view>
+							<image class="photo" :src="liveItem.goodsCard?.imgUrl"></image>
+							<view class="item">
+								<view class="price"><text class="red">¥{{liveItem.goodsCard?.price}} </text><text
+										class="del">¥{{liveItem.goodsCard?.otPrice}}</text></view>
+								<view class="title oneline-hide">{{liveItem.goodsCard?.productName}}</view>
+								<view class="button"
+									@click="goShop(liveItem.goodsCard?.productId,liveItem.goodsCard?.goodsId)">立即抢购
+								</view>
+							</view>
+						</view>
+					</u-popup>
+
+					<!-- 抽奖 -->
+					<u-popup :show="isShowLotteryPop" @close="!isShowLotteryPop" 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>
+							<image class="bg-img " src="/static/images/red_bg.png"></image>
+							<view class="prize-content">
+								<view class="u-flex-row-reverse u-flex mr20">
+									<u-icon name="close" color="#fff" size="20"
+										@click="isShowLotteryPop=false"></u-icon>
+								</view>
+								<view class="column align-center ">
+									<image class="w446 h80" src="/static/images/red_title.png"></image>
+									<view class="fs24 colorf u-flex-y-center mt30 mb30">
+										52人已参与,开奖倒计时
+										<view class="white-item">14</view>:
+										<view class="white-item">344</view>:
+										<view class="white-item">44</view>
+									</view>
+									<!-- 	<view class="item-group">
+										<view class="item" v-for="(item,index) in lotteryProducts" :key="index">
+											<image class="w280 h280" :src="item.imgUrl"></image>
+											<view v-show="true" class="title">{{item.prizeLevel}}等奖</view>
+											<view v-show="true" class="txt">{{item.productName}}</view>
+										</view>
+										<view class="item center">
+											<image class="w280 h280" src="/static/images/img.png"></image>
+											<view v-show="true" class="title">二等奖</view>
+											<view v-show="true" class="txt">新用户免费领礼品弹窗</view>
+										</view>
+
+										<view class="item">
+											<image class="w280 h280" src="/static/images/img.png"></image>
+											<view v-show="false" class="title">二等奖</view>
+											<view v-show="false" class="txt">新用户免费领礼品弹窗</view>
+										</view>
+									</view>
+									<view class="point-group"  v-for="(item,index) in lotteryProducts" :key="index">
+										<view class="item" v-if="item.length" :class="{ selected: activePointIndex === 0 }"
+											@click="activePointIndex = 0"></view>
+										<view class="item" :class="{ selected: activePointIndex === 1 }"
+											@click="() => { activePointIndex = 1; scrollToCenterItem() }"></view>
+										<view class="item" :class="{ selected: activePointIndex === 2 }"
+											@click="activePointIndex = 2"></view>
+									</view> -->
+
+
+									<swiper class="prize-swiper" :current="activePointIndex"
+										@change="onPrizeSwiperChange" :circular="false" :duration="300"
+										indicator-dots="false">
+										<swiper-item v-for="(product, idx) in lotteryProducts" :key="idx">
+											<view class="item" :class="{center: idx === 1}">
+												<image class="w280 h280" :src="product.imgUrl"></image>
+												<view class="title">{{product.prizeLevel}}等奖</view>
+												<view class="txt">{{product.productName}}</view>
+											</view>
+										</swiper-item>
+									</swiper>
+
+									<view class="point-group" v-if="lotteryProducts.length > 0">
+										<view class="item" v-for="(_, idx) in lotteryProducts" :key="idx"
+											:class="{ selected: activePointIndex === idx }"
+											@click="activePointIndex = idx"></view>
+									</view>
+
+									<view class="colorf  fs28">
+										观看直播参与抽奖
+									</view>
+									<view class="button" @click="">参与抽奖</view>
+								</view>
+							</view>
+						</view>
+					</u-popup>
+
+					<u-popup :show="liveItem.integral?.status" @close="!liveItem.integral?.status" round='20rpx'
+						mode="center" bgColor='#ffffff'>
+						<view class="integral-box">
+							<view class="top">
+								<view class="title">观看视频领芳华币</view>
+								<image class="photo" src="/static/images/integral.png" mode="widthFix"></image>
+							</view>
+
+							<view class="item">
+								<view class="title ">{{liveItem.integral?.msg}}</view>
+								<view class="button" @click="liveItem.integral.status=flase">确认</view>
+							</view>
+						</view>
+					</u-popup>
+
+					<!-- 观众列表弹窗 -->
+					<u-popup :show="showadd" @close="close" @open="openViews" round='20rpx' bgColor='#ffffff'>
+						<view class="view-box">
+							<view class="t-c fs30">在线观众</view>
+							<scroll-view scroll-y class="scroll-content" :style="{height: scrollHeight + 'px'}"
+								@scrolltolower="handleScrollToLower">
+								<view class="fs24 u-flex-y-center mb20" 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 :src="item.avatar||$img.logo" size="32"></u-avatar>
+									<text class="ml16">{{item.nickName||"未命名"}}</text>
+								</view>
+								<view class="no-more" v-if="viewNoMoreData && liveViewers.length > 0">
+									<text>没有更多了</text>
+								</view>
+							</scroll-view>
+						</view>
+					</u-popup>
+
+					<!-- 商品弹窗 -->
+					<u-popup :show="liveItem.shopping" @close="closeShop" @open="openShop" round='20rpx'
+						bgColor='f3f5f9'>
+						<view class="shoppop">
+							<view class="shoppop-top">
+								<u-avatar :src="store.logoUrl" size="36" class="ml16"></u-avatar>
+								<view class="search-input u-flex-y-center">
+									<image class="w24 mr16" src="/static/images/search.png" mode="widthFix">
+									</image>
+									<input placeholder="请搜索商品" v-model="liveItem.inputInfo"
+										@input="handleSearchInput" />
+								</view>
+								<view class="t-c search-top" @click="goOrderList(liveItem)">
+									<image class="w48 h48" src="/static/images/order.png"></image>
+									<view>订单</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 :src="item.imgUrl" mode="widthFix"></image>
+										<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 u-flex-y-center">
+												<view class="collect-btn">
+													<image v-if="item.isFavorite" @click="onGoodsCollect(item)"
+														class="w36 h36" src="/static/images/collect_select.png">
+													</image>
+													<image v-else @click="onGoodsCollect(item)" class="w36 h36"
+														src="/static/images/collect.png">
+													</image>
+												</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>
+						</view>
+					</u-popup>
+				</view>
+			</swiper-item>
+		</swiper>
+	</view>
+</template>
+<script>
+	import Hls from 'hls.js';
+	import CryptoJS from 'crypto-js'
+	import {
+		liveList
+	} from '@/api/list'
+	import {
+		liveLottery, // 抽奖查询
+		liveRed, // 点击领红包
+		liveDataLike, // 点赞
+		collectStore, // 店铺收藏/取消收藏
+		collectGoods, // 商品收藏/取消收藏
+		// store, // 查询店铺
+		// showGoods, //弹出商品卡片
+		// follow, // 关注/取消关注
+		watchUserList, //获取直播间用户(展示在线用户)
+		liveMsg, //获取最近聊天记录
+		// 小黄车
+		liveStore, //店铺展示,
+		// liveGoodsDetail, //商品详情,
+		liveOrderUser, //正在购买
+		getLiveInfo, //获取直播间信息接口
+		getLiveViewData, //直播间点赞、关注、在线人数数据
+		currentActivities //红包 卡片 抽奖
+	} from '@/api/live'
+	import {
+		liveOrderList, // 订单列表
+	} from '@/api/order'
+
+	import parse from '/uni_modules/uview-plus/libs/config/props/parse';
+	import {
+		LiveWS
+	} from '@/utils/liveWS.js'
+	import {
+		getlive,
+		// gettextlist,
+		getAnswerlist,
+		submitAnswer
+	} from '@/api/home'
+	// var wsUrl = "wss://live.test.ylrztop.com/ws/live-api/app/webSocket"; //余红奇
+	var wsUrl = "ws://192.168.10.166:7114/app/webSocket"; //余红奇
+	// var wsUrl = "ws://192.168.10.125:7114/app/webSocket"; //涂小龙
+	// var wsUrl = "ws://live.test.ylrztop.com/prod-api/app/webSocket"; //余红奇
+	// var wsUrl = "ws://nd383294.natappfree.cc/app/webSocket"; //余红奇
+	// var wsUrl = "ws://v56c9b8e.natappfree.cc/app/webSocket"; //余红奇
+	// var wsUrl = "ws://192.168.10.170:7114/app/webSocket"; //陈果
+	// var wsUrl = "ws://live.ylrzcloud.com/socket/app/webSocket";
+	var pingpangTimes = null;
+	var initTimes = null;
+	var isSocketOpen = false;
+	var socket = null;
+
+	export default {
+		data() {
+			return {
+				lotteryProducts: [],
+
+				activePointIndex: 0,
+
+				lotteryTimer: null,
+				redTimer: null,
+
+				isShowLotteryPop: false,
+				isShowLottery: false,
+				isShowRed: false,
+				// 新增:滑动节流相关变量
+				lastSwiperChangeTime: 0, // 上次切换时间戳
+				swiperChangeThrottle: 300, // 切换节流阈值(毫秒)
+
+
+				lastClickTime: 0,
+				clickDelay: 300, // 300ms内只响应一次点击
+
+				connectingLiveId: null, // 记录正在连接的直播间ID
+				swiperDuration: 0, // 初始化为0,首次加载无动画
+				videoRetryCounts: {}, // 记录每个直播间的视频重试次数,格式: { liveId: 次数 }
+
+
+				socketInstances: {}, // 改为对象存储多个socket实例
+				currentSwiperIndex: 0, // 当前swiper索引
+				list: [], // 直播间列表
+				// preloading: false, // 预加载状态
+
+
+				liveUserTotal: null,
+				viewPageSize: 10, // 每页数量
+				viewPageNum: 1, // 当前页码
+				viewLoading: false, // 是否正在加载
+				viewNoMoreData: false, // 是否没有更多数据
+				scrollHeight: 0,
+				scrollTimer: null, // 滚动防抖定时器
+
+
+				socketInstance: null, // 统一管理 socket 实例
+				reconnectCount: 0,
+				maxReconnectAttempts: 3,
+				isManualClose: false, // 标记是否手动关闭
+
+				showRed: true,
+				searchTimer: null,
+				reconnectTimer: null,
+				isCollect: false,
+				showPurchasePrompt: false,
+				purchasePromptTimer: null,
+				prevOrderCount: 0, // 用于记录上一次的购买人数
+				videoUrl: null,
+				showType: 1, //横屏1 竖屏2
+				boxHeight: 300, //小黄车高度
+				liveViewers: [], //观众
+				likeName: 0,
+				hlsPlayer: null, // HLS播放器实例,
+				livingUrl: "",
+				products: {},
+				store: {},
+				orderUser: {}, //正在购买
+				userType: 0,
+				timestamp: '',
+				liveId: null,
+				userinfo: '', //用户信息
+				// path: 'http://192.168.10.166/dev-api', //余红奇
+				// path: 'http://v56c9b8e.natappfree.cc', //余红奇
+				// path: 'live.test.ylrztop.com/prod-api', //余红奇
+				// value: '',
+				talkdisabled: false, //输入框是否禁用
+				autoplay: false, //视频自动播放
+				showadd: false,
+				scrollIntoView: '',
+				videoContext: '',
+				livedata: {}, //直播间点赞、关注、在线人数数据
+
+			};
+		},
+
+
+		onLoad(options) {
+			this.initTime();
+			if (options.liveId) {
+				this.liveId = options.liveId; // 仅当 liveId 变化时更新
+			}
+			this.userinfo = JSON.parse(uni.getStorageSync("userInfo"))
+			// 初始化直播间列表
+			this.initLiveList(options);
+			// this.getliveUser(false); // 调用获取在线用户接口
+			const platform = uni.getWindowInfo().platform;
+			// 初始化直播间列表
+
+			if (['mp-weixin', 'mp-alipay', 'mp-baidu', 'mp-toutiao'].includes(platform)) {
+				// 确保 API 存在再调用
+				if (uni.showShareMenu) {
+					uni.showShareMenu({
+						withShareTicket: true, // 可选参数,根据需求配置
+						success: () => {
+							console.log('分享菜单显示成功');
+						},
+						fail: (err) => {
+							console.error('分享菜单显示失败:', err);
+						}
+					});
+				} else {
+					console.warn('当前平台不支持 uni.showShareMenu');
+				}
+			}
+			this.getCurrentActivities(options.liveId);
+		},
+		onReady() {
+			// 页面渲染完成后,默认让中间item居中
+			this.$nextTick(() => {
+				if (this.activePointIndex === 1) { // 默认选中第二个point
+					this.scrollToCenterItem();
+				}
+			});
+		},
+		onShareAppMessage() {
+			return {
+				title: this.livedata.liveName,
+				path: '/pages/home/living',
+				imageUrl: this.products.image,
+				success(res) {
+					console.log("分享成功", res);
+				},
+				fail(err) {
+					console.error("分享失败", err);
+				}
+			};
+		},
+		computed: {
+			filteredViewers() {
+				// 若 liveViewers 是 null/undefined/非数组,返回空数组
+				if (!Array.isArray(this.liveViewers)) {
+					return [];
+				}
+				return this.liveViewers.slice(0, 3);
+			}
+		},
+		onHide() {
+			const currentLive = this.list[this.currentSwiperIndex];
+			if (currentLive) {
+				this.pauseVideo(currentLive);
+				this.clearTimeTimer(currentLive); // 隐藏时清除当前直播间定时器
+			} // 隐藏时关闭所有连接
+			this.closeAllWebSockets();
+		},
+		onUnload() {
+			// 清除所有直播间的时间定时器
+			this.list.forEach(liveItem => {
+				this.clearTimeTimer(liveItem);
+			});
+			// 关闭所有WebSocket连接
+			this.closeAllWebSockets();
+			this.socketInstances = {}; // 强制清空实例对象
+			// 移除所有全局事件监听
+			this.removeAllEventListeners();
+
+			// 清理定时器
+			this.clearAllTimers();
+
+			// 销毁HLS播放器(如果使用了hls.js)
+			if (this.hlsPlayer) {
+				this.hlsPlayer.destroy();
+				this.hlsPlayer = null;
+			}
+
+			this.list.forEach(liveItem => {
+				const videoId = `myVideo_${liveItem.liveId}`;
+				const videoContext = uni.createVideoContext(videoId, this);
+				if (videoContext) {
+					videoContext.pause(); // 仅暂停视频即可
+				}
+			});
+
+			// Object.values(this.tempState.redTimer).forEach(timer => clearInterval(timer));
+			// Object.values(this.tempState.lotteryTimer).forEach(timer => clearInterval(timer));
+			// Object.values(this.tempState.searchTimer).forEach(timer => clearTimeout(timer));
+			// clearTimeout(this.tempState.scrollTimer);
+			// 2. 关闭所有 WebSocket 连接
+			this.closeAllWebSockets();
+			// 3. 销毁视频上下文
+			this.list.forEach(liveItem => {
+				const videoCtx = uni.createVideoContext(`myVideo_${liveItem.liveId}`, this);
+				if (videoCtx) videoCtx.destroy(); // 销毁视频上下文
+			});
+			// 4. 清空响应式数据
+			this.list = [];
+			this.socketInstances = {};
+		},
+		watch: {
+			// 监听orderUser.count的变化
+			'orderUser.count': {
+				handler(newVal, oldVal) {
+					if (newVal !== this.prevOrderCount) {
+						this.prevOrderCount = newVal;
+						this.showPurchaseMessage();
+					}
+				},
+				immediate: true
+			}
+		},
+		methods: {
+			onPrizeSwiperChange(e) {
+				// 同步指示点与轮播当前索引
+				this.activePointIndex = e.detail.current;
+			},
+
+
+			scrollToCenterItem() {
+				this.$nextTick(() => { // 确保DOM渲染完成后再获取位置
+					// 1. 获取父容器(item-group)的DOM信息
+					const groupQuery = uni.createSelectorQuery().in(this);
+					groupQuery.select('.item-group')
+						.boundingClientRect(groupRect => {
+							if (!groupRect) return; // 防止DOM未找到
+
+							// 2. 获取中间item(索引为1的item)的DOM信息
+							const itemQuery = uni.createSelectorQuery().in(this);
+							itemQuery.selectAll('.item-group .item')
+								.boundingClientRect(itemsRect => {
+									if (!itemsRect || itemsRect.length < 3) return; // 确保有3个item
+
+									const centerItemRect = itemsRect[1]; // 中间的item(索引1)
+									const groupWidth = groupRect.width; // 父容器宽度
+									const itemWidth = centerItemRect.width; // 单个item宽度
+									const itemGap = 20; // item之间的间距(对应CSS中的gap:20rpx)
+
+									// 3. 计算滚动距离:让中间item的中心点与父容器中心点对齐
+									// 公式:滚动距离 = 中间item左侧距离 - (父容器宽度 - 中间item宽度)/2
+									const scrollLeft = centerItemRect.left - (groupWidth - itemWidth - 2 *
+										itemGap) / 2;
+
+									// 4. 让父容器滚动到指定位置(平滑滚动)
+									uni.createSelectorQuery().in(this)
+										.select('.item-group')
+										.node(node => {
+											if (node) {
+												node.scrollLeft = scrollLeft; // 直接设置滚动距离(如需平滑可加过渡)
+											}
+										})
+										.exec();
+								})
+								.exec();
+						})
+						.exec();
+				});
+			},
+			onLiveStateChange(e, liveItem) {
+				// console.log('直播状态变化:', e.detail.code, e.detail);
+				// 可以根据状态码处理不同的直播状态
+				const stateCode = e.detail.code;
+				// 2001: 已经连接服务器
+				// 2002: 已经连接服务器,开始拉流
+				// 2003: 网络接收到首个视频数据包(IDR)
+				// 2004: 视频播放开始
+				// 2005: 视频播放进度
+				// 2006: 视频播放结束
+				// 2007: 视频播放Loading
+				// 2008: 解码器启动
+				// -2301: 网络断连,且经多次重连抢救无效,更多重试请自行重启播放
+				// -2302: 获取加速拉流地址失败
+			}, // 直播错误事件
+			onLiveError(e, liveItem) {
+				this.videoError(e, liveItem);
+			},
+
+
+			//  红包 卡片 抽奖
+			getCurrentActivities(liveItem) {
+				if (!liveItem.liveId) return;
+				// const res = currentActivities(liveId);
+				currentActivities(liveItem.liveId).then(res => {
+						if (res.code == 200) {
+							// 商品卡片
+							this.$set(liveItem, 'goodsCard', res.goods);
+							// 红包
+							this.$set(liveItem, 'redInfo', res.red[0]);
+							this.isShowRed = true
+							// 抽奖
+							this.$set(liveItem, 'lotteryInfo', res.lottery[0]);
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			// 计算当前时间与 liveItem.startTime 的差值,并更新 totalTime
+			calculateTimeDiff(liveItem) {
+				if (!liveItem.startTime) {
+					liveItem.totalTime = '00小时00分钟00秒';
+					return;
+				}
+				const iosCompatibleTime = liveItem.startTime
+					.replace(/-/g, '/')
+					.replace(' ', ' ');
+				const startTime = new Date(liveItem.startTime);
+				const now = new Date();
+				if (isNaN(startTime.getTime())) {
+					console.warn(`iOS 时间解析失败,原始时间:${liveItem.startTime},转换后:${iosCompatibleTime}`);
+					liveItem.totalTime = '00小时00分钟00秒';
+					return;
+				}
+				const diffMs = Math.max(0, now - startTime);
+
+				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(liveItem, 'totalTime', `${hours}:${minutes}:${seconds}`);
+			},
+
+			padZero(num) {
+				return num < 10 ? `0${num}` : num;
+			},
+
+			// 启动当前直播间的时间差值定时器
+			startTimeTimer(liveItem) {
+				// 先清除当前直播间的旧定时器(避免重复)
+				if (liveItem.timeTimer) {
+					clearInterval(liveItem.timeTimer);
+				}
+
+				// 立即计算一次(避免等待1秒才显示)
+				this.calculateTimeDiff(liveItem);
+
+				//  每秒更新一次(实时刷新)
+				liveItem.timeTimer = setInterval(() => {
+					this.calculateTimeDiff(liveItem);
+				}, 1000);
+			},
+			// 清除指定直播间的时间定时器
+			clearTimeTimer(liveItem) {
+				if (liveItem.timeTimer) {
+					clearInterval(liveItem.timeTimer);
+					liveItem.timeTimer = null; // 清空定时器标识
+				}
+			},
+
+
+
+			toggleViewerList() {
+				const now = Date.now()
+				if (now - this.lastClickTime > this.clickDelay) {
+					this.showadd = !this.showadd
+					this.lastClickTime = now
+				}
+			},
+			// 重置在线用户列表的分页参数
+			resetUserListParams() {
+				this.viewPageNum = 1; // 重置页码为第一页
+				this.viewNoMoreData = false; // 重置“没有更多数据”状态
+				this.liveViewers = []; // 清空现有列表
+			},
+			closeAllWebSockets() {
+				this.isManualClose = true;
+
+				// 关闭所有连接
+				Object.keys(this.socketInstances).forEach(liveId => {
+					try {
+						if (this.socketInstances[liveId] && this.socketInstances[liveId].instance) {
+							this.socketInstances[liveId].instance.close({
+								code: 1000,
+								reason: '页面关闭'
+							});
+							console.log(`直播间 ${liveId} WebSocket 已关闭`);
+						}
+					} catch (e) {
+						console.error(`关闭直播间 ${liveId} WebSocket 时出错:`, e);
+					}
+				});
+
+				this.socketInstances = {};
+				isSocketOpen = false;
+			}, // 移除所有全局事件监听器
+			removeAllEventListeners() {
+				uni.$off('initSocket');
+				uni.$off('sendMsg');
+				uni.$off('closeWebSocket');
+				uni.$off('refreshOrder');
+				// 可以根据实际情况添加其他需要移除的事件
+			}, // 清理所有定时器
+			clearAllTimers() {
+				if (this.intervalId) {
+					clearInterval(this.intervalId);
+					this.intervalId = null;
+				}
+
+				if (this.pingpangTimes) {
+					clearInterval(this.pingpangTimes);
+					this.pingpangTimes = 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;
+				}
+			},
+			// 初始化当前直播间数据
+			async initCurrentLiveData() {
+				const currentLive = this.list[this.currentSwiperIndex];
+				if (!currentLive || !currentLive.liveId) {
+					return;
+				}
+
+				// 设置加载状态
+				currentLive.loading = true;
+
+				try {
+					// 先初始化WebSocket连接
+					await this.initSocket(currentLive);
+
+					// 然后并行加载其他数据
+					await Promise.allSettled([
+						this.getLiveMsg(currentLive),
+						this.getCurrentActivities(currentLive),
+						this.getliveViewData(currentLive),
+						// this.getShowGoods(currentLive),
+						this.getliving(currentLive)
+					]);
+
+					currentLive.loaded = true;
+					// 初始化完成后,启动当前直播间的时间差值定时器
+					this.startTimeTimer(currentLive);
+				} catch (error) {
+					console.error("初始化直播间数据失败:", error);
+				} finally {
+					currentLive.loading = false;
+				}
+			},
+
+
+			// 初始化直播间列表
+			async initLiveList(options) {
+				try {
+					await this.getList(); // 先加载直播间列表
+					if (this.list.length === 0) {
+						console.error("直播间列表为空,无法初始化");
+						return;
+					}
+
+					// 设置初始直播间索引(原逻辑保留)
+					if (options.liveId) {
+						const index = this.list.findIndex(item => item.liveId == options.liveId);
+						this.currentSwiperIndex = index !== -1 ? index : 0;
+					} else {
+						this.currentSwiperIndex = 0;
+					}
+
+					// 延迟设置动画时间(原逻辑保留)
+					setTimeout(() => {
+						this.swiperDuration = 300;
+					}, 100);
+
+					// 获取当前直播间的liveItem
+					const currentLive = this.list[this.currentSwiperIndex];
+					if (currentLive) {
+						this.liveId = currentLive.liveId;
+
+						// 重置用户列表参数
+						this.resetUserListParams();
+
+						// 预加载相邻直播间(不初始化WebSocket)
+						this.preloadNearbyLives(false);
+
+						// 初始化当前直播间数据(包含WebSocket连接)
+						await this.initCurrentLiveData();
+
+						// // 获取在线用户
+						// this.getliveUser(false);
+
+						// 延迟播放视频
+						setTimeout(() => {
+							this.playVideo(currentLive);
+						}, 500);
+					}
+				} catch (error) {
+					console.error("初始化失败:", error);
+				}
+			},
+
+			// Swiper切换事件
+			async onSwiperChange(e) {
+				const now = Date.now();
+				const newIndex = e.detail.current;
+				const oldIndex = this.currentSwiperIndex;
+
+				// 相同索引或节流期间,不处理
+				if (newIndex === oldIndex) return;
+				if (now - this.lastSwiperChangeTime < this.swiperChangeThrottle) {
+					console.log('Swiper切换过快,已节流');
+					return;
+				}
+
+				// 更新最后切换时间
+				this.lastSwiperChangeTime = now;
+
+				// 1. 立即关闭旧直播间的WebSocket(同步操作)
+				const oldLive = this.list[oldIndex];
+				if (oldLive) {
+					// 关闭旧Socket
+					this.closeWebSocket(oldLive.liveId);
+					// 清除旧心跳定时器
+					clearInterval(this.pingpangTimes);
+					this.pingpangTimes = null;
+				}
+				if (this.redTimer) {
+					clearInterval(this.redTimer);
+					this.redTimer = null;
+				}
+				if (this.lotteryTimer) {
+					clearInterval(this.lotteryTimer);
+					this.lotteryTimer = null;
+				}
+				this.closeShop()
+				if (oldLive) {
+					this.pauseVideo(oldLive);
+					this.clearTimeTimer(oldLive); // 清除旧直播间的时间定时器
+					// 强制关闭并删除实例,确保连接被释放
+					if (this.socketInstances[oldLive.liveId]) {
+						try {
+							this.socketInstances[oldLive.liveId].instance.close({
+								code: 1000,
+								reason: '切换直播间'
+							});
+							console.log(`关闭旧直播间 ${oldLive.liveId} WebSocket`);
+						} catch (e) {
+							console.error('关闭旧连接失败:', e);
+						}
+						delete this.socketInstances[oldLive.liveId]; // 彻底删除实例
+					}
+				}
+
+				// 2. 处理新直播间(后续逻辑不变)
+				this.currentSwiperIndex = newIndex;
+				const newLive = this.list[newIndex];
+				if (!newLive) return;
+
+				this.liveId = newLive.liveId;
+				this.resetUserListParams();
+				await this.initCurrentLiveData(); // 内部会启动新直播间的定时器
+				// this.getliveUser(false);
+				setTimeout(() => {
+					this.playVideo(newLive);
+				}, 100);
+			},
+			// 获取直播间列表
+			async getList() {
+				const data = {
+					page: 1,
+					page_size: 20
+				};
+				try {
+					const res = await liveList(data);
+					if (res.code === 200) {
+						this.list = res.rows.map(item => ({
+							...item,
+							talklist: [],
+							loading: false,
+							loaded: false,
+							shopping: false,
+							inputInfo: '',
+							showWelcomeMessage: false,
+							redInfo: {},
+							goodsCard: {},
+							totalTime: '00小时00分钟00秒', // 初始化差值为0
+							timeTimer: null, // 存储当前直播间的定时器,用于后续清理
+							// 预处理:统一将 startTime 转换为 iOS 兼容格式(避免重复转换)
+							startTime: item.startTime ? item.startTime.replace(/-/g, '/') : ''
+						}));
+						console.log("直播间列表加载成功,数量:", this.list.length); // 确认数量是否 > 0
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: "none"
+						});
+						this.list = []; // 接口失败时清空列表,避免后续错误
+					}
+				} catch (error) {
+					console.error("获取直播间列表失败:", error);
+					this.list = []; // 异常时清空列表
+				}
+			},
+			// 播放视频
+			playVideo(liveItem) {
+				if (!liveItem) return;
+
+				try {
+					// 直播流使用live-player
+					if (liveItem.liveType === 1 && liveItem.livingUrl) {
+						const livePlayerId = `myLivePlayer_${liveItem.liveId}`;
+						const livePlayerContext = uni.createLivePlayerContext(livePlayerId, this);
+						if (livePlayerContext) {
+							livePlayerContext.play();
+						}
+					}
+					// 回放视频使用video
+					else if (liveItem.liveType === 2 && liveItem.videoUrl) {
+						const videoId = `myVideo_${liveItem.liveId}`;
+						const videoContext = uni.createVideoContext(videoId, this);
+						if (videoContext) {
+							videoContext.pause(() => {
+								videoContext.play();
+							});
+						}
+					}
+				} catch (error) {
+					console.error("播放视频失败:", error);
+				}
+			},
+
+			pauseVideo(liveItem) {
+				if (!liveItem) return;
+
+				try {
+					// 直播流使用live-player
+					if (liveItem.liveType === 1) {
+						const livePlayerId = `myLivePlayer_${liveItem.liveId}`;
+						const livePlayerContext = uni.createLivePlayerContext(livePlayerId, this);
+						if (livePlayerContext) {
+							livePlayerContext.pause();
+						}
+					}
+					// 回放视频使用video
+					else if (liveItem.liveType === 2) {
+						const videoId = `myVideo_${liveItem.liveId}`;
+						const videoContext = uni.createVideoContext(videoId, this);
+						if (videoContext) {
+							videoContext.pause();
+						}
+					}
+				} catch (error) {
+					console.error("暂停视频失败:", error);
+				}
+			},
+			// 预加载相邻直播间
+			async preloadNearbyLives(includeWebSocket = false) {
+				// this.preloading = true;
+				const currentIndex = this.currentSwiperIndex;
+				const preloadIndexes = [];
+
+				// 只预加载数据,不初始化WebSocket(强制关闭WebSocket预加载)
+				if (currentIndex > 0) preloadIndexes.push(currentIndex - 1);
+				if (currentIndex < this.list.length - 1) preloadIndexes.push(currentIndex + 1);
+
+				for (const index of preloadIndexes) {
+					const liveItem = this.list[index];
+					if (!liveItem || liveItem.loaded || liveItem.loading) continue;
+
+					liveItem.loading = true;
+					try {
+						// 只加载基础数据,不初始化WebSocket
+						await Promise.all([
+							this.getliving(liveItem),
+							this.getLiveMsg(liveItem),
+							this.getCurrentActivities(liveItem),
+							this.getliveViewData(liveItem),
+							// this.getShowGoods(liveItem)
+						]);
+						liveItem.loaded = true;
+					} catch (error) {
+						liveItem.loaded = false;
+					} finally {
+						liveItem.loading = false;
+					}
+				}
+				// this.preloading = false;
+			},
+
+
+			openViews() {
+				// 计算scroll-view高度
+				this.$nextTick(() => {
+					const query = uni.createSelectorQuery().in(this);
+					query.select('.view-box').boundingClientRect(data => {
+						if (data) {
+							// 减去标题和底部固定区域的高度
+							this.scrollHeight = data.height - 80 - 120; // 80是标题高度,120是底部高度
+						}
+					}).exec();
+				});
+			},
+			// 重置直播间数据
+			resetLiveData() {
+				// 保留不需要重置的数据(如用户信息等)
+				const keepData = {
+					userinfo: this.userinfo,
+					list: this.list,
+					currentSwiperIndex: this.currentSwiperIndex
+				};
+
+				// 重置其他直播间特定数据
+				this.liveUserTotal = null;
+				// this.liveViewData = {};
+				this.liveViewers = [];
+				this.livingUrl = "";
+				this.videoUrl = null;
+				this.products = {};
+				this.store = {};
+				this.orderUser = {};
+				this.talklist = [];
+				this.livedata = {};
+				// this.isFollow = false;
+				this.shopping = false;
+				this.inputInfo = ''
+
+				// 恢复需要保留的数据
+				Object.assign(this, keepData);
+			},
+
+			// 获取直播间用户
+			async getliveUser(isLoadMore = false) {
+				// 强制使用当前 liveId,避免使用旧值
+				const currentLiveId = this.liveId;
+				if (!currentLiveId) return;
+				// if (this.viewLoading || this.viewNoMoreData) return;
+				this.viewLoading = true;
+				try {
+					const res = await watchUserList(currentLiveId, this.viewPageSize, this.viewPageNum, false);
+					if (res.code === 200) {
+						// 若请求期间已切换直播间,忽略旧数据
+						if (this.liveId !== currentLiveId) return;
+						this.liveUserTotal = res.total;
+						if (res.rows.length === 0) {
+							this.viewNoMoreData = true;
+							return;
+						}
+
+						this.liveViewers = isLoadMore ? [...this.liveViewers, ...res.rows] : res
+							.rows; // 首次加载/切换直播间时重置数据
+						this.viewPageNum++;
+						// console.log("在线观众", this.liveViewers)
+					}
+				} catch (error) {
+					console.error('获取观众列表失败:', error);
+				} finally {
+					this.viewLoading = false;
+				}
+			},
+			// 滚动到底部触发
+			handleScrollToLower() {
+				clearTimeout(this.tempState.scrollTimer);
+				this.tempState.scrollTimer = setTimeout(() => {
+					if (!this.viewLoading && !this.viewNoMoreData) {
+						this.getliveUser(true);
+					}
+				}, 300);
+			},
+			async getLiveMsg(liveItem) {
+				// 强化校验:确保 liveItem 存在且包含 liveId
+				if (!liveItem || !liveItem.liveId) {
+					return; // 直接返回,不执行后续逻辑
+				}
+
+				try {
+					const res = await liveMsg(liveItem.liveId, 30, 1);
+					if (res.code == 200) {
+						const rows = Array.isArray(res.rows) ? res.rows : [];
+						const reversedTalkList = [...rows].reverse();
+						this.$set(liveItem, 'talklist', reversedTalkList);
+
+						this.$nextTick(() => {
+							// 滚动到最新消息(反转后最新消息在数组最后一位,索引为 reversedTalkList.length - 1)
+							this.$set(liveItem, 'scrollIntoView', `list_${reversedTalkList.length - 1}`);
+						});
+					}
+				} catch (error) {
+					console.error("获取聊天记录失败:", error);
+				}
+			},
+
+			// 点击抽奖
+			onLottery(item) {
+				if (!item.lotteryInfo) return;
+				let data = {
+					lotteryId: item.lotteryInfo.lotteryId
+				}
+				console.log("dian", data)
+				// 抽奖查询
+				liveLottery(data).then(res => {
+						// this.isShowLottery=false
+						this.isShowLotteryPop = true
+						if (res.code == 200) {
+							this.lotteryProducts = res.data.products
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			// 点击红包
+			onRed(item) {
+				// console.log("点了this.liveId", item)
+				if (!item.liveId) return;
+				if (!item.redInfo?.redId) return;
+
+				let data = {
+					liveId: item.liveId,
+					userId: this.userinfo.userId,
+					redId: item.redInfo.redId,
+				}
+				liveRed(data).then(res => {
+						this.isShowRed = false
+						if (res.code == 200) {
+							console.log(this.isShowRed)
+							console.log("点了this.liveId", liveItem.redInfo)
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			handleSearchInput(liveItem) {
+				clearTimeout(this.tempState.searchTimer[liveItem.liveId]); // 清除旧定时器
+				this.tempState.searchTimer[liveItem.liveId] = setTimeout(() => {
+					this.queryCollect(liveItem);
+				}, 500);
+			},
+
+			// 显示购买提示信息
+			showPurchaseMessage() {
+				// 清除之前的定时器
+				if (this.purchasePromptTimer) {
+					clearTimeout(this.purchasePromptTimer);
+				}
+
+				// 显示提示
+				this.showPurchasePrompt = true;
+
+				// 2秒后自动隐藏
+				this.purchasePromptTimer = setTimeout(() => {
+					this.showPurchasePrompt = false;
+				}, 2000);
+			},
+			truncateString(str, maxLength) {
+				return str.length > maxLength ? str.slice(0, maxLength) + '...' : str;
+			},
+			goStore(item) {
+				console.log("带过去storeId", item)
+				if (!item.storeId) {
+					uni.showToast({
+						title: "当前直播间暂未开通店铺",
+						icon: 'none'
+					});
+					return;
+				}
+
+				uni.navigateTo({
+					url: '/pages_shop/store?liveId=' + item.liveId + "&storeId=" + item.storeId
+				})
+			},
+			// 去订单列表
+			goOrderList() {
+				uni.navigateTo({
+					url: "/pages_shop/order"
+				})
+			},
+
+			// 初始化HLS播放器
+			initHlsPlayer() {
+				if (Hls.isSupported() && this.livingUrl) {
+					const video = document.getElementById('myVideo');
+					if (video) {
+						this.hlsPlayer = new Hls();
+						this.hlsPlayer.loadSource(this.livingUrl);
+						this.hlsPlayer.attachMedia(video);
+						this.hlsPlayer.on(Hls.Events.MANIFEST_PARSED, () => {
+							video.play();
+						});
+					}
+				}
+			},
+
+			// 视频错误处理
+			videoError(e, liveItem) {
+				const maxRetry = 3;
+				const retryDelay = 3000; // 3秒后重试
+				if (!this.tempState.videoRetry[liveItem.liveId]) {
+					this.tempState.videoRetry[liveItem.liveId] = 0;
+				}
+				if (this.tempState.videoRetry[liveItem.liveId] >= maxRetry) {
+					uni.showToast({
+						title: "视频加载失败,请检查网络"
+					});
+					return;
+				}
+				this.tempState.videoRetry[liveItem.liveId]++;
+				setTimeout(() => {
+					if (liveItem.liveId === this.liveId) {
+						this.playVideo(liveItem);
+					}
+				}, retryDelay);
+			},
+
+			// 修改获取直播信息方法
+			async getliving(liveItem) {
+				if (!liveItem || !liveItem.liveId) return;
+				// console.log("获取直播信息:", liveItem.liveId);
+				const param = {
+					id: liveItem.liveId
+				};
+
+				try {
+					const res = await getlive({
+						id: liveItem.liveId
+					});
+					if (res.code !== 200) {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+						return;
+					}
+
+					// 强制更新视频源(覆盖旧值)
+					if (res.data.liveType === 2) {
+						// 回放视频
+						this.$set(liveItem, 'videoUrl', res.data.videoUrl);
+						this.$set(liveItem, 'livingUrl', ''); // 清空直播流
+						this.$set(liveItem, 'placeholderText', "说点什么...");
+
+					} else if (res.data.liveType === 1) {
+						// 直播流
+						this.$set(liveItem, 'livingUrl', res.data.flvHlsUrl);
+						this.$set(liveItem, 'videoUrl', ''); // 清空回放视频
+						this.$set(liveItem, 'placeholderText', "说点什么...");
+					} else {
+						// 未开播
+						this.$set(liveItem, 'livingUrl', '');
+						this.$set(liveItem, 'videoUrl', '');
+					}
+
+					// 更新其他直播信息
+					// 仅当是当前激活的直播间时,才允许自动播放
+					const isCurrentLive = this.currentSwiperIndex === this.list.findIndex(item => item.liveId ===
+						liveItem.liveId);
+					this.$set(liveItem, 'autoplay', isCurrentLive && res.data.liveType !== 0);
+					this.$set(liveItem, 'showType', res.data.showType);
+					this.$set(liveItem, 'storeId', res.storeId);
+					this.queryCollect();
+				} catch (err) {
+					console.error("获取直播信息失败:", err);
+					uni.showToast({
+						title: "获取直播信息失败",
+						icon: 'none'
+					});
+				}
+			}, // 设置视频播放
+			setupVideoPlayback(liveItem, liveData) {
+				if (!liveItem.livingUrl) return;
+
+				// H5 平台:使用 HLS.js 处理 .m3u8 流
+				// #ifdef H5
+				if (liveItem.livingUrl.includes('.m3u8')) {
+					this.initHlsPlayer(liveItem);
+					return;
+				}
+				// #endif
+
+				// 小程序/App 平台:直接使用 video 组件
+				const videoId = `myVideo_${liveItem.liveId}`;
+				const videoContext = uni.createVideoContext(videoId, this);
+
+				if (liveData.liveType === 1) {
+					// 回放:跳转到指定位置
+					videoContext.seek(liveData.nowDuration || 0);
+				} else {
+					// 直播:直接播放
+					videoContext.play();
+				}
+			},
+			maskString(str, maskChar = '*') {
+				// 如果str是undefined或null,直接返回空字符串
+				if (!str) return '';
+				// 确保str是字符串(如果是数字等类型,先转为字符串)
+				const strVal = String(str);
+				return strVal.split('').map((char, index) => (index === 0 ? char : maskChar)).join('');
+			},
+
+			getPureDecimal(num, precision = 6) {
+				const decimalPart = Math.abs(num).toFixed(precision).split('.')[1];
+				return decimalPart?.replace(/0+$/, '') || ''; // 移除末尾多余的0
+			},
+
+			// 返回上一个页面并关闭WebSocket
+			goBack() {
+				// 暂停当前视频
+				const currentLive = this.list[this.currentSwiperIndex];
+				if (currentLive) {
+					this.pauseVideo(currentLive);
+				}
+
+				// 关闭所有WebSocket连接
+				this.closeWebSocket();
+
+				// 导航返回
+				const pages = getCurrentPages();
+				if (pages.length > 1) {
+					uni.navigateBack();
+				} else {
+					uni.reLaunch({
+						url: '/pages/list/index'
+					});
+				}
+			},
+
+			//正在购买
+			async getliveOrder() {
+				const currentLiveId = this.liveId;
+				if (!currentLiveId) return;
+
+				try {
+					const res = await liveOrderUser(currentLiveId);
+					if (res.code === 200) {
+						// 绑定到当前 liveItem
+						const currentLive = this.list[this.currentSwiperIndex];
+						if (currentLive) {
+							this.$set(currentLive, 'orderUser', res);
+							this.orderUser = res; // 同步全局变量
+						}
+					}
+				} catch (error) {
+					console.error('获取正在购买用户失败:', error);
+				}
+			},
+
+			// 获取直播间信息接口
+			getLiveinformation() {
+				if (!this.liveId) return;
+				getLiveInfo(this.liveId).then(res => {
+						if (res.code == 200) {
+							console.log("获取直播间信息接口>>>>", res)
+							this.livingUrl = res.livingUrl
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+
+
+			// 点赞
+			async onLike(liveItem) {
+				if (!liveItem || !liveItem.liveId) return;
+				try {
+					const res = await liveDataLike(liveItem.liveId);
+					if (res?.like) {
+						liveItem.liveViewData.like++; // 只更新当前直播间的点赞数
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+					}
+				} catch (error) {
+					console.error('点赞失败:', error);
+				}
+			},
+
+			//直播间点赞、关注、在线人数数据
+			async getliveViewData(liveItem) {
+				if (!liveItem || !liveItem.liveId) return;
+				try {
+					const res = await getLiveViewData(liveItem.liveId);
+					if (res.code == 200) {
+						// 强制响应式更新,确保数据实时显示
+						this.$set(liveItem, 'liveViewData', res);
+					}
+				} catch (error) {
+					console.error("获取直播间数据失败:", error);
+					// 失败时兜底,避免显示异常
+					this.$set(liveItem, 'liveViewData', {
+						like: 0,
+						watchCount: 0
+					});
+				}
+			},
+			//弹出商品卡片
+			// async getShowGoods(liveItem) {
+			// 	if (!liveItem || !liveItem.liveId) return;
+			// 	try {
+			// 		const res = await showGoods(liveItem.liveId);
+			// 		if (res.code == 200) {
+			// 			this.$set(liveItem, 'goodsCard', res);
+			// 		}
+			// 	} catch (error) {
+			// 		console.error("暂无商品卡片", error);
+			// 	}
+			// },
+			// 去购买,跳商品详情
+			goShop(productId, goodsId) {
+				const currentLive = this.list[this.currentSwiperIndex];
+				if (!currentLive || !currentLive.liveId) return;
+				uni.navigateTo({
+					url: '/pages_shop/goods?productId=' + productId + '&liveId=' + currentLive.liveId +
+						'&goodsId=' + goodsId + '&storeId=' + currentLive.storeId
+				})
+			},
+
+			// 查询店铺
+			async queryCollect() {
+				const currentLive = this.list[this.currentSwiperIndex];
+				if (!currentLive || !currentLive.liveId) return;
+
+				const {
+					storeId
+				} = currentLive;
+				if (!storeId) return;
+				try {
+					const res = await liveStore(currentLive.liveId, currentLive.inputInfo);
+					if (res.code === 200) {
+						// 数据绑定到当前 liveItem,避免全局污染
+						this.$set(currentLive, 'products', res.data);
+						// this.$set(currentLive, 'store', res.data);
+						// 同步更新全局变量(供弹窗使用)
+						this.products = res.data;
+						// this.store = res.data;
+					}
+				} catch (error) {
+					console.error('获取小黄车商品失败:', error);
+				}
+			},
+
+			// 店铺收藏
+			onStoreCollect(liveItem) {
+				console.log("店铺收藏", liveItem)
+				if (!liveItem.storeId) return;
+				collectStore(liveItem.storeId).then(res => {
+						if (res.code == 200) {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+							liveItem.store.isFavorite = !liveItem.store.isFavorite
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					},
+					rej => {}
+				);
+			},
+			// 商品收藏
+			onGoodsCollect(item) {
+				console.log("商品收藏", 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 => {}
+				);
+			},
+			// 关注
+			// async onFollow(liveItem) {
+			// 	if (!liveItem || !liveItem.liveId) return;
+
+			// 	try {
+			// 		const res = await follow(liveItem.liveId);
+			// 		liveItem.isFollow = !liveItem.isFollow;
+			// 		uni.showToast({
+			// 			title: res.msg,
+			// 			icon: 'none'
+			// 		});
+			// 	} catch (error) {
+			// 		console.error("关注操作失败:", error);
+			// 	}
+			// },
+			// 时间戳
+			initTime() {
+				const now = new Date();
+				this.timestamp = now.getTime(); // 例如:'2023-04-01 12:00:00'
+			},
+			openShop() {
+
+			},
+			openViews() {
+				this.$nextTick(() => {
+					const query = uni.createSelectorQuery().in(this);
+					query.select('.view-box').boundingClientRect(data => {
+						if (data) {
+							this.scrollHeight = data.height - 80 - 120;
+						}
+					}).exec();
+				});
+			},
+			openCart(liveItem) {
+				if (!liveItem.storeId) {
+					uni.showToast({
+						title: "当前直播间暂未开通店铺",
+						icon: 'none'
+					});
+					return;
+				}
+				liveItem.shopping = true
+			},
+			close() {
+				this.showadd = false;
+				const scrollView = uni.createSelectorQuery().in(this).select('.scroll-content');
+				scrollView.offScroll(); // 移除滚动监听
+			},
+
+			// 关闭小黄车
+			closeShop() {
+				// 通过当前swiper索引获取当前直播间实例
+				const currentLive = this.list[this.currentSwiperIndex];
+				if (currentLive) {
+					this.$set(currentLive, 'shopping', false);
+				}
+			},
+			getEWechatSdk() {
+				// 只在H5平台执行
+				// #ifdef H5
+				let eWechatSdk = '';
+				if (/(Android)/i.test(navigator.userAgent)) {
+					eWechatSdk = 'jWeixin';
+				} else if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
+					eWechatSdk = 'wx';
+				} else {
+					eWechatSdk = 'jWeixin';
+				}
+				uni.setStorageSync("wxSdk", eWechatSdk);
+				// #endif
+			},
+			// 修改关闭WebSocket方法
+			closeWebSocket(liveId = null) {
+				this.isManualClose = true;
+				clearInterval(this.pingpangTimes);
+				clearInterval(this.reconnectTimer);
+
+				if (liveId) {
+					// 添加空值检查
+					if (this.socketInstances[liveId] && this.socketInstances[liveId].instance) {
+						try {
+							this.socketInstances[liveId].instance.close();
+						} catch (e) {}
+					}
+					delete this.socketInstances[liveId];
+				} else {
+					Object.keys(this.socketInstances).forEach(id => {
+						// 添加空值检查
+						if (this.socketInstances[id] && this.socketInstances[id].instance) {
+							try {
+								this.socketInstances[id].instance.close();
+							} catch (e) {}
+						}
+					});
+					this.socketInstances = {};
+				}
+				isSocketOpen = false;
+			},
+			startHeartbeat(liveId) {
+				clearInterval(this.pingpangTimes);
+				this.pingpangTimes = setInterval(() => {
+					const inst = this.socketInstances[liveId];
+					if (!inst || !inst.isOpen || !inst.instance) return;
+					const pingData = {
+						cmd: 'ping',
+						timestamp: Date.now()
+					};
+					try {
+						inst.instance.send({
+							data: JSON.stringify(pingData)
+						});
+					} catch (err) {
+						this.scheduleReconnect(liveId);
+					}
+				}, 30000);
+			},
+			async initSocket(liveItem) {
+				if (this.currentSwiperIndex !== this.list.findIndex(item => item.liveId === liveItem.liveId)) {
+					return; // 只连接当前直播间
+				}
+				const currentLive = this.list[this.currentSwiperIndex];
+				if (!currentLive || currentLive.liveId !== liveItem.liveId) {
+					return;
+				}
+				if (!liveItem || !liveItem.liveId) return;
+
+				const liveId = liveItem.liveId;
+
+				// 检查是否已经是当前连接或正在连接
+				if (this.connectingLiveId === liveId ||
+					(this.socketInstances[liveId] && this.socketInstances[liveId].isOpen)) {
+					return;
+				}
+
+				// 检查是否是当前活跃的直播间
+				if (this.currentSwiperIndex !== this.list.findIndex(item => item.liveId === liveId)) {
+					return;
+				}
+				this.socketInstances[liveId] = {
+					instance: null,
+					isOpen: false
+				};
+				// 关闭之前的连接(如果存在)
+
+				this.closeWebSocket(liveId);
+
+				// 设置正在连接的直播间ID
+				this.connectingLiveId = liveId;
+
+				// 防止重复创建
+				if (this.reconnectCount >= this.maxReconnectAttempts) {
+					this.connectingLiveId = null;
+					return;
+				}
+
+				this.isManualClose = false;
+				const connectTimeout = setTimeout(() => {
+					if (!this.socketInstances[liveId]?.isOpen) {
+						console.error(`WebSocket连接超时: ${liveId}`);
+						this.scheduleReconnect(liveId);
+					}
+				}, 10000); // 10秒超时
+				// 生成签名
+				const signature = CryptoJS.HmacSHA256(
+					`${liveId}${this.userinfo.userId}${this.userType}${this.timestamp}`,
+					this.timestamp.toString()
+				).toString(CryptoJS.enc.Hex);
+
+				// 初始化实例状态
+				this.socketInstances[liveId] = {
+					instance: null,
+					isOpen: false
+				};
+
+				try {
+					const socketTask = uni.connectSocket({
+						url: `${wsUrl}?userId=${this.userinfo.userId}&liveId=${liveId}&userType=${this.userType}&timestamp=${this.timestamp}&signature=${signature}`,
+						success: () => {},
+						fail: (err) => {
+							this.connectingLiveId = null;
+							this.scheduleReconnect(liveId);
+						}
+					});
+
+					socketTask.onOpen((res) => {
+						console.log('WebSocket 连接已成功建立', res);
+						this.socketInstances[liveId].instance = socketTask;
+						this.socketInstances[liveId].isOpen = true;
+						clearTimeout(connectTimeout);
+						isSocketOpen = true;
+						this.connectingLiveId = null;
+						this.reconnectCount = 0;
+						this.startHeartbeat(liveId); // 修改 startHeartbeat 以接受 liveId 并使用 socketTask.send
+					});
+
+					socketTask.onMessage((res) => {
+						// 找到对应的直播间并更新数据
+						const targetLive = this.list.find(item => item.liveId === liveId);
+						if (targetLive) {
+							this.handleSocketMessage(res, targetLive);
+						}
+					});
+
+					socketTask.onError((err) => {
+						clearTimeout(connectTimeout);
+						this.connectingLiveId = null;
+						this.scheduleReconnect(liveId);
+					});
+
+					socketTask.onClose(() => {
+						console.log(`WebSocket 连接已关闭: ${liveId}`);
+						this.connectingLiveId = null;
+					});
+				} catch (e) {
+					console.error('创建 WebSocket 异常:', e);
+					this.connectingLiveId = null;
+					this.scheduleReconnect(liveId);
+				}
+			},
+			// 处理Socket消息
+			handleSocketMessage(message, liveItem) {
+				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') {
+						// 1. 将消息追加到当前直播间的talklist中(响应式更新)
+						this.$set(liveItem, 'talklist', [...(liveItem.talklist || []), messageData]);
+						// 2. 延迟下一帧滚动到最新消息(确保DOM已更新)
+						this.$nextTick(() => {
+							const lastIndex = liveItem.talklist.length - 1;
+							this.$set(liveItem, 'scrollIntoView', `list_${lastIndex}`);
+						});
+					} else if (socketMessage.cmd == 'red') {
+						this.$set(liveItem, 'redInfo', JSON.parse(socketMessage.data));
+						this.isShowRed = true
+						this.redTimer = setInterval(() => {
+							this.isShowRed = true
+						}, liveItem.redInfo.duration * 1000)
+					} else if (socketMessage.cmd == 'lottery') {
+						this.$set(liveItem, 'lotteryInfo', JSON.parse(socketMessage.data));
+						this.isShowlottery = true
+						this.lotteryTimer = setInterval(() => {
+							this.isShowlottery = true
+						}, liveItem.lotteryInfo.duration * 1000)
+					} else if (socketMessage.cmd == 'entry' || socketMessage.cmd == 'out') {
+						this.$set(liveItem, 'talklist', [...liveItem.talklist, messageData]);
+						this.$set(liveItem, 'showWelcomeMessage', false);
+						this.$set(liveItem, 'showWelcomeMessage', true);
+						this.getliveUser(false);
+						if (liveItem.welcomeTimer) clearTimeout(liveItem.welcomeTimer);
+						liveItem.welcomeTimer = setTimeout(() => {
+							this.$set(liveItem, 'showWelcomeMessage', false);
+						}, 1000);
+					} else if (socketMessage.cmd == 'Integral') {
+						let integral = {
+							msg: socketMessage.msg,
+							status: true
+						}
+						this.$set(liveItem, 'integral', integral);
+					} else if (socketMessage.cmd == 'blockUser') {
+						uni.removeStorage({
+							key: 'AppToken',
+							success: () => {
+								uni.reLaunch({
+									url: '/pages/auth/login'
+								});
+							}
+						});
+					} else if (socketMessage.cmd == 'goods') {
+						this.$set(liveItem, 'goodsCard', JSON.parse(socketMessage.data));
+					}
+				} else {
+					uni.showToast({
+						title: data.msg,
+						icon: 'none'
+					});
+				}
+			},
+			scheduleReconnect(liveId) {
+				if (this.isManualClose || this.reconnectCount >= this.maxReconnectAttempts) return;
+				this.reconnectCount++;
+				const delay = Math.min(3000 * this.reconnectCount, 30000);
+				clearInterval(this.reconnectTimer);
+				this.reconnectTimer = setTimeout(() => {
+					// 使用传入的liveId
+					const liveItem = this.list.find(item => item.liveId === liveId) || {
+						liveId
+					};
+					this.initSocket(liveItem);
+				}, delay);
+			},
+			sendMsg(liveItem) {
+				if (!liveItem || !liveItem.liveId) return;
+				// 防止连续点击发送两次(短时锁定)
+				if (liveItem.isSending) return;
+				liveItem.isSending = true;
+				setTimeout(() => {
+					liveItem.isSending = false;
+				}, 800); // 800ms 内禁止再次发送
+
+				const text = (liveItem.value || '').trim();
+				if (!text) {
+					uni.showToast({
+						title: "不能发送空消息",
+						icon: 'none'
+					});
+					return;
+				}
+
+				const liveId = liveItem.liveId;
+				const socketItem = this.socketInstances[liveId];
+				this.$set(liveItem, 'value', ''); // 立即清空输入框,提升体验
+				// 检查socket连接状态
+				if (!socketItem || !socketItem.instance || !socketItem.isOpen) {
+					this.initSocket(liveItem); // 尝试重连
+					uni.showToast({
+						title: "连接未建立,正在重连",
+						icon: 'none'
+					});
+					return;
+				}
+
+				// 构造发送给服务端的消息数据
+				const data = {
+					liveId,
+					userId: this.userinfo.userId,
+					userType: 0,
+					cmd: "sendMsg", // 指令标识,服务端会根据此返回sendMsg消息
+					msg: text,
+					nickName: this.userinfo.nickName,
+					avatar: this.userinfo.avatar
+				};
+
+				// 发送socket消息
+				try {
+					socketItem.instance.send({
+						data: JSON.stringify(data),
+						success: () => {
+							// 发送成功无需额外操作,等待服务端返回消息后再更新列表
+						},
+						fail: (err) => {
+							uni.showToast({
+								title: err,
+								icon: 'none'
+							});
+							// 发送失败时可恢复输入框内容
+							this.$set(liveItem, 'value', text);
+						}
+					});
+				} catch (err) {}
+			}
+
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	.live-player {
+		width: 100%;
+		height: 100%;
+	}
+
+	.swiper-wrapper {
+		position: relative;
+		width: 100%;
+		height: 100vh;
+		overflow: hidden;
+		background-color: #000000;
+	}
+
+	.swiper-container {
+		width: 100%;
+		height: 100vh;
+	}
+
+	.container {
+		width: 100%;
+		height: 100%;
+		position: relative;
+		transition: opacity 0.3s ease;
+		transform: translateZ(0); // 开启GPU加速
+		will-change: opacity; // 告诉浏览器提前优化该属性
+
+	}
+
+	.loading-tip {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		z-index: 10;
+
+		.loading-text {
+			color: #ffffff;
+			font-size: 28rpx;
+			margin-top: 20rpx;
+		}
+	}
+
+	.loading-more,
+	.no-more {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		padding: 20rpx 0;
+		color: #999;
+		font-size: 24rpx;
+	}
+
+	.loading-more {
+		flex-direction: column;
+	}
+
+	.preload-indicator {
+		position: absolute;
+		top: 50%;
+		right: 30rpx;
+		transform: translateY(-50%);
+		z-index: 100;
+		background: rgba(0, 0, 0, 0.5);
+		border-radius: 50%;
+		padding: 16rpx;
+	}
+
+	/* button自带样式清除 */
+	.student-orther-icon button::after {
+		border: none !important;
+		padding: 0 !important;
+		margin: 0 !important;
+	}
+
+	.student-orther-icon button {
+		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;
+	}
+
+	.welcome-message {
+		position: fixed;
+		width: 100%;
+		bottom: 460rpx;
+		left: 50%;
+		transform: translateX(-50%);
+		color: white;
+		padding: 10px 20px;
+		border-radius: 20px;
+		// animation: fadeOut 1s ease 1s forwards;
+		z-index: 1000;
+		transition: opacity 0.3s ease;
+	}
+
+	@keyframes fadeOut {
+		from {
+			opacity: 1;
+		}
+
+		to {
+			opacity: 0;
+		}
+	}
+
+	.send {
+		background-color: #fafafa;
+		border-radius: 28rpx;
+		padding: 14rpx 16rpx;
+		color: #181818;
+		font-weight: 500;
+	}
+
+	// .container {
+	// 	position: relative;
+	// 	width: 100%;
+	// 	height: 100vh;
+	// 	overflow: hidden;
+	// }
+
+	// .talktext {
+	// 	border-radius: 8rpx;
+	// 	background-color: rgba(255, 255, 255, 0.1);
+
+	// 	view {
+	// 		width: 100%;
+	// 	}
+	// }
+
+	.talk-list {
+		border-radius: 30rpx;
+		background-color: rgba(33, 33, 33, 0.5);
+		padding: 10rpx 30rpx;
+	}
+
+	// .zoom-button-active {
+	// 	transform: scale(1.5);
+	// }
+
+	// .background-image {
+	// 	position: absolute;
+	// 	top: 0;
+	// 	left: -40rpx;
+	// 	width: 110%;
+	// 	height: 110%;
+	// 	object-fit: cover;
+	// 	filter: blur(20px);
+	// 	z-index: 0;
+	// }
+
+	// .background-images {
+	// 	position: absolute;
+	// 	top: 0;
+	// 	left: -40rpx;
+	// 	width: 110%;
+	// 	height: 110%;
+	// 	object-fit: cover;
+	// 	filter: blur(20px);
+	// 	z-index: 6;
+	// }
+
+	// .blackbg {
+	// 	position: absolute;
+	// 	top: 0;
+	// 	left: 0;
+	// 	width: 100%;
+	// 	height: 100%;
+	// 	background: rgba(0, 0, 0, 0.7);
+	// 	object-fit: cover;
+	// 	filter: blur(10px);
+	// 	z-index: 1;
+	// }
+
+	.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: 220rpx;
+			left: 30rpx;
+			z-index: 5;
+			display: flex;
+			align-items: center;
+
+			.item-box {
+				border-radius: 16rpx;
+				background-color: rgba(77, 77, 77, 0.5);
+				width: 80rpx;
+				height: 90rpx;
+				margin-right: 20rpx;
+				position: relative;
+
+				.tip {
+					position: absolute;
+					width: 100%;
+					bottom: 0;
+					color: #fafcff;
+					font-size: 20rpx;
+					background-color: rgba(15, 15, 15, 0.8);
+					border-radius: 16rpx;
+					text-align: center;
+				}
+
+				.item {
+					margin: 0 auto;
+					padding: 10rpx 0;
+
+					image {
+						height: 100%;
+					}
+				}
+			}
+		}
+
+
+		.siderow-group {
+			position: absolute;
+			top: 65%;
+			right: 30rpx;
+			z-index: 9;
+			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 {
+					background-color: transparent;
+					margin: 0;
+					line-height: 1;
+					padding: 0;
+				}
+
+				.image {
+					width: 72rpx;
+					height: 72rpx;
+				}
+			}
+		}
+
+		.side-group {
+			position: absolute;
+			// top: 30%;
+			top: 65%;
+			right: 30rpx;
+			z-index: 9;
+			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 {
+					background-color: transparent;
+					margin: 0;
+					line-height: 1;
+					padding: 0;
+				}
+
+				.image {
+					width: 72rpx;
+					height: 72rpx;
+				}
+			}
+		}
+
+		
+	.goods {
+		position: fixed;
+		// bottom: 160rpx;
+		// right: 10rpx;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		z-index: 5;
+		background-color: #fff;
+		border-radius: 20rpx;
+		overflow: hidden;
+		width: 300rpx;
+		// width: 220rpx;
+		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: 10rpx;
+				font-size: 20rpx;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				border-radius: 10rpx;
+			}
+		}
+
+		.photo {
+			width: 100%;
+			height: 250rpx;
+			border-radius: 16rpx 16rpx 0 0;
+			overflow: hidden;
+		}
+
+		.item {
+			padding: 4rpx;
+
+			.price {
+				.red {
+					color: #FF5701;
+					font-weight: 600;
+					margin-right: 10rpx;
+				}
+
+				.del {
+					color: #828282;
+					font-weight: 500;
+					font-size: 24rpx;
+					text-decoration: line-through
+				}
+			}
+
+			.title {
+				font-weight: 500;
+				font-size: 26rpx;
+				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;
+			}
+
+		}
+
+	}
+
+	// 抽奖
+	.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;
+
+			.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;
+			}
+
+			.prize-swiper {
+				width: 100%;
+				height: 400rpx;
+				margin: 20rpx 0;
+				overflow: visible;
+				/* 轮播项基础样式 */
+				.item {
+					flex-shrink: 0;
+					width: 348rpx;
+					height: 348rpx;
+					background: #FFFFFF;
+					box-shadow: 0rpx 12rpx 19rpx 2rpx rgba(219, 73, 22, 0.6);
+					border-radius: 24rpx;
+					border: 4rpx solid #FFCA96;
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+					box-sizing: border-box;
+					padding: 20rpx 0;
+					margin: 0 auto;
+					transition: all 0.3s ease;
+				
+					&:not(.center) {
+						transform: scale(0.85);
+						z-index: 1;
+						opacity: 0.8;
+					}
+				
+					&.center {
+						width: 440rpx;
+						height: 450rpx;
+						transform: scale(1);
+						z-index: 2;
+						opacity: 1;
+						box-shadow: 0rpx 16rpx 24rpx 4rpx rgba(219, 73, 22, 0.8);
+						border-color: #FFEB66;
+					}
+				
+					.title {
+						font-weight: 500;
+						font-size: 32rpx;
+						color: #222222;
+						margin: 20rpx 0 10rpx;
+					}
+				
+					.txt {
+						font-size: 24rpx;
+						color: #757575;
+						text-align: center;
+						padding: 0 10rpx;
+					}
+				
+					image {
+						width: 220rpx;
+						height: 220rpx;
+						object-fit: cover;
+						border-radius: 16rpx;
+					}
+				}
+			}
+
+			
+
+			/* 5. 指示点样式优化 */
+			.point-group {
+				margin: 30rpx 0 50rpx;
+				display: flex;
+				gap: 12rpx;
+				justify-content: center;
+
+				.item {
+					width: 24rpx;
+					height: 8rpx;
+					background: rgba(255, 255, 255, 0.5);
+					border-radius: 4rpx;
+					transition: all 0.3s ease;
+
+					&.selected {
+						background: #FFEB66;
+					}
+				}
+			}
+
+
+
+			.item-group {
+				position: absolute;
+				top: 250rpx;
+				left: 0;
+				width: 100%;
+				display: flex;
+				align-items: center;
+				overflow: hidden;
+				overflow-x: auto; // 仅横向滚动
+				overflow-y: hidden;
+				gap: 20rpx;
+				padding: 0 20rpx; // 左右留间隙,避免item贴边
+				scroll-behavior: smooth; // 平滑滚动(关键)
+				scrollbar-width: none; // 隐藏滚动条(可选,美化)
+				-ms-overflow-style: none; // IE隐藏滚动条
+
+				.item {
+					flex-shrink: 0;
+					width: 348rpx;
+					height: 348rpx;
+					background: #FFFFFF;
+					box-shadow: 0rpx 12rpx 19rpx 2rpx rgba(219, 73, 22, 0.6);
+					border-radius: 24rpx 24rpx 24rpx 24rpx;
+					border: 4rpx solid #FFCA96;
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+					box-sizing: border-box;
+					padding: 20rpx 0;
+
+					.title {
+						font-weight: 500;
+						font-size: 32rpx;
+						color: #222222;
+						margin: 20rpx 0 20rpx;
+					}
+
+					.txt {
+						font-size: 24rpx;
+						color: #757575;
+					}
+				}
+
+				.center {
+					width: 440rpx;
+					height: 450rpx;
+				}
+			}
+
+			// .point-group {
+			// 	margin: 480rpx 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;
+
+			}
+		}
+
+
+	}
+
+
+	.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;
+			}
+		}
+
+
+		
+		}
+	}
+
+</style>

+ 5 - 5
pages/list/index.vue

@@ -4,19 +4,19 @@
 			:down="downOption" :up="upOption">
 			<view class="list">
 				<view class="list-item" @click="goLive(item)" v-for="(item,index) in list" :key="index">
-					<!-- <image v-if="item.liveImgUrl" :src="item.liveImgUrl"></image> -->
+					<image v-if="item.liveImgUrl" :src="item.liveImgUrl"></image>
 					<!-- 直播流 -->
-					<video v-if=" item.liveType == 1 && item.flvHlsUrl" :id="'myVideo_' + item.liveId"
+					<!-- <video v-if=" item.liveType == 1 && item.flvHlsUrl" :id="'myVideo_' + item.liveId"
 						:src="item.flvHlsUrl" :autoplay="false" muted  :controls="false" object-fit="contain"
 						:custom-cache="false" :enable-progress-gesture="false" :show-center-play-btn="false"
-						:http-cache="false" :muted="true" @error="onVideoError(item, $event)"></video>
+						:http-cache="false" :muted="true" @error="onVideoError(item, $event)"></video> -->
 
 					<!-- 录播视频 -->
-					<video v-if=" item.liveType == 2 && item.videoUrl " :id="'myVideo_' + item.liveId"
+				<!-- 	<video v-if=" item.liveType == 2 && item.videoUrl " :id="'myVideo_' + item.liveId"
 						:src="item.videoUrl" :autoplay="false" muted  :controls="false" object-fit="contain"
 						:custom-cache="false" :enable-progress-gesture="false" :show-center-play-btn="false"
 						:http-cache="false" :loop="true" :muted="true" @error="onVideoError(item, $event)"
-						@loadedmetadata="onVideoLoaded(item)"></video>
+						@loadedmetadata="onVideoLoaded(item)"></video> -->
 
 					<view class="info">
 						<text>{{item.liveName}}</text>

BIN
static/images/like.png


BIN
static/images/lottery.png


BIN
static/images/share.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
unpackage/dist/dev/mp-weixin/api/live.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
unpackage/dist/dev/mp-weixin/common/assets.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
unpackage/dist/dev/mp-weixin/pages/home/living.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
unpackage/dist/dev/mp-weixin/pages/home/living.wxml


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
unpackage/dist/dev/mp-weixin/pages/list/index.js


+ 1 - 1
unpackage/dist/dev/mp-weixin/pages/list/index.wxml

@@ -1 +1 @@
-<view class="content data-v-7bd28468"><mescroll-body wx:if="{{f}}" class="r data-v-7bd28468" u-s="{{['d']}}" u-r="mescrollRef" bindinit="{{c}}" binddown="{{d}}" bindup="{{e}}" u-i="7bd28468-0" bind:__l="__l" u-p="{{f}}"><view class="list data-v-7bd28468"><view wx:for="{{a}}" wx:for-item="item" wx:key="l" class="list-item data-v-7bd28468" bindtap="{{item.k}}"><video wx:if="{{item.a}}" class="data-v-7bd28468" id="{{item.b}}" src="{{item.c}}" autoplay="{{false}}" muted controls="{{false}}" object-fit="contain" custom-cache="{{false}}" enable-progress-gesture="{{false}}" show-center-play-btn="{{false}}" http-cache="{{false}}" muted="{{true}}" binderror="{{item.d}}"></video><video wx:if="{{item.e}}" class="data-v-7bd28468" id="{{item.f}}" src="{{item.g}}" autoplay="{{false}}" muted controls="{{false}}" object-fit="contain" custom-cache="{{false}}" enable-progress-gesture="{{false}}" show-center-play-btn="{{false}}" http-cache="{{false}}" loop="{{true}}" muted="{{true}}" binderror="{{item.h}}" bindloadedmetadata="{{item.i}}"></video><view class="info data-v-7bd28468"><text class="data-v-7bd28468">{{item.j}}</text></view></view></view></mescroll-body></view>
+<view class="content data-v-7bd28468"><mescroll-body wx:if="{{f}}" class="r data-v-7bd28468" u-s="{{['d']}}" u-r="mescrollRef" bindinit="{{c}}" binddown="{{d}}" bindup="{{e}}" u-i="7bd28468-0" bind:__l="__l" u-p="{{f}}"><view class="list data-v-7bd28468"><view wx:for="{{a}}" wx:for-item="item" wx:key="e" class="list-item data-v-7bd28468" bindtap="{{item.d}}"><image wx:if="{{item.a}}" class="data-v-7bd28468" src="{{item.b}}"></image><view class="info data-v-7bd28468"><text class="data-v-7bd28468">{{item.c}}</text></view></view></view></mescroll-body></view>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
unpackage/dist/dev/mp-weixin/pages_shop/storeOrder.js


BIN
unpackage/dist/dev/mp-weixin/static/images/like.png


BIN
unpackage/dist/dev/mp-weixin/static/images/lottery.png


BIN
unpackage/dist/dev/mp-weixin/static/images/share.png


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels