绿满眶商城微信小程序-uniapp
xiangpei
7 天以前 8cdb055657aff3167f38b31e41ccfe4b684ba457
pages/tabbar/index/home.vue
@@ -9,52 +9,98 @@
      @change="onSwiperChange"
    >
      <swiper-item v-for="(item, index) in videoList" :key="item.id">
      <!-- 播放按钮(仅当视频暂停时显示) -->
      <view
        class="play-icon"
        @click="togglePlay(index)"
        v-if="!currentVideoIsPlaying"
      >
        <image src="/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image>
      <view style="width: 100%;height: 100%;" v-if="item.videoContentType === 'video'">
           <!-- 播放按钮(仅当视频暂停时显示) -->
           <view
            class="play-icon"
            @click="togglePlay(index)"
            v-if="!currentVideoIsPlaying"
           >
            <image src="/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image>
           </view>
           <video
            :id="'video'+index"
            :ref="'video'+index"
            :src="item.videoUrl"
            :autoplay="currentIndex === index"
            :controls="false"
            :loop="true"
            :object-fit="item.objectFit"
            :enable-progress-gesture="false"
            class="video-item"
            @play="onPlay(item.id, index)"
            @pause="onPause(index)"
            @ended="onEnded(index)"
            @click="togglePlay(index)"
            @timeupdate="onTimeUpdate($event)"
            @loadedmetadata="onLoadedMetadata($event)"
           ></video>
           <!-- 自定义控制条 -->
           <view
            @touchstart="handleTouchStart"
            @touchmove="handleTouchMove"
            @touchend="handleTouchEnd"
            class="container">
            <!-- 进度条 - 整个区域可拖动 -->
            <view class="process-warp" :style="{ opacity: showProcess ? 1 : 0 }">
              <!-- 显示当前进度 -->
              <view class="progress-text">{{ hasPlayTime }}/{{formartDuration}}</view>
              <view
               class="progress-bar"
               id="progressBar"
              >
               <!-- 已填充部分 -->
               <view class="progress-fill" :style="{ width: progress + '%' }"></view>
              </view>
            </view>
           </view>
      </view>
        <video
          :id="'video'+index"
        :ref="'video'+index"
          :src="item.videoUrl"
          :autoplay="currentIndex === index"
          :controls="false"
          :loop="true"
        :object-fit="item.objectFit"
          class="video-item"
          @play="onPlay(item.id, index)"
          @pause="onPause(index)"
          @ended="onEnded(index)"
        @click="togglePlay(index)"
        @timeupdate="onTimeUpdate($event)"
        ></video>
      <view style="width: 100%; height: 100%;" v-else-if="item.videoContentType === 'img'">
        <uni-swiper-dot
         :info="item.imgs"
         :current="currentImgIndex"
         mode="round"
         style="width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;"
         :dots-styles="{width: 24, bottom: 24,selectedBackgroundColor: 'green', backgroundColor: 'gray'}"
         >
          <swiper class="swiper-box" @change="imgChange" :autoplay="true" :interval="3000">
            <swiper-item v-for="img in item.imgs" :key="img">
              <view class="swiper-item">
                <!-- 调整 image 样式,使其居中且按比例缩放 -->
                <image
                  :src="img"
                  mode="aspectFit"
                  style="width: 100%; height: 100%; display: block; margin: 0 auto;"
                ></image>
              </view>
            </swiper-item>
          </swiper>
        </uni-swiper-dot>
      </view>
      
      <!-- 悬挂商品链接层 -->
      <view class="goods-link-warp">
      <view class="goods-link-warp" v-if="item.goodsList.length > 0">
         <view class="goods-link">
           <view class="goods-container">
             <!-- 商品图片 -->
             <image class="goods-image" :src="item.goods.imageUrl" mode="aspectFill"></image>
             <!-- 商品信息 -->
             <view class="goods-info">
               <text class="goods-name">{{item.goods.name}}</text>
               <view class="price-section">
                 <text class="current-price">¥{{item.goods.price}}</text>
                 <text class="original-price" v-if="item.goods.originalPrice">¥{{item.goods.originalPrice}}</text>
               </view>
               <text class="sales-count">{{item.goods.saleNum}}人已购</text>
             </view>
             <!-- 购买按钮 -->
             <view class="buy-button">
               <text>购买</text>
             </view>
           </view>
           <swiper @change="goodsChange" :autoplay="true" :interval="4000" style="height: 120rpx;">
            <swiper-item v-for="goods in item.goodsList" :key="goods.goodsId">
              <view class="goods-container" @click="jumpToPay(item.id)">
               <!-- 商品图片 -->
               <image class="goods-image" :src="goods.thumbnail" mode="aspectFill"></image>
               <!-- 商品信息 -->
               <view class="goods-info">
                 <text class="goods-name">{{goods.goodsName}}</text>
                 <view class="price-section">
                  <text class="current-price">¥{{goods.price}}</text>
                  <text class="original-price" v-if="goods.originalPrice">¥{{goods.originalPrice}}</text>
                 </view>
               </view>
              </view>
            </swiper-item>
           </swiper>
         </view>
      </view>
      
@@ -66,14 +112,14 @@
        </view>
          <view style="width: 100%;word-wrap: break-word;white-space: normal;overflow-wrap: break-word;">
           <text class="video-title">{{item.title}}</text>
           <text class="video-tag" v-for="(tag, index) in item.tagList" :key="tag">#{{tag.tagName}}</text>
           <text class="video-tag" v-for="(tag, index) in item.tagList" :key="tag.id">#{{tag.tagName}}</text>
        </view>
        </view>
        
        <!-- 右侧互动按钮 -->
       <view class="action-buttons">
         <view class="avatar-container">
            <image class="avatar" :src="item.authorAvatar" mode="aspectFill"></image>
            <image class="avatar" @click="jumpToHomePage(item.authorId)" :src="item.authorAvatar" mode="aspectFill"></image>
            <!-- 关注图标 - 使用绝对定位 -->
            <view v-if="!item.subscribeThisAuthor" class="follow-icon" @click="subscribeAuth(index, item.authorId)">
             <text class="iconfont">&#xe629;</text>
@@ -88,6 +134,12 @@
            <text class="iconfont">&#xe7f7;</text>
            <text style="font-size: 10px;font-weight: lighter;">{{item.commentNum}}</text>
          </view>
        <view class="action-item">
           <button open-type="share" class="custom-share-btn" :data-obj="item">
                 <text class="iconfont">&#xe602;</text>
               </button>
        </view>
        </view>
      
      </swiper-item>
@@ -97,7 +149,11 @@
   <uni-popup ref="commentPopup" type="bottom" :is-mask-click="true" @maskClick="closeCommentPopup">
     <view class="comment-popup">
       <view class="popup-header">
         <text class="popup-title">评论({{commentsTotal}})</text>
         <text class="popup-title" v-if="!commentForm.replyId">评论({{commentsTotal}})</text>
        <view class="reply-title" v-else>
          <text>回复 @{{commentForm.replyUserNickname}}</text>
          <text class="cancel-reply" @click="cancelReply">取消</text>
        </view>
         <text class="iconfont close-icon" @click="closeCommentPopup">&#xe675;</text>
       </view>
       
@@ -110,25 +166,61 @@
           暂无评论,快来发表第一条评论吧~
         </view>
         
         <view v-else class="comment-item" v-for="comment in comments" :key="comment.id">
           <image class="avatar" :src="comment.userAvatar || '/static/default-avatar.png'"></image>
           <view class="comment-content">
             <text class="nickname">{{comment.userNickname}}</text>
             <text class="content">{{comment.commentContent}}</text>
             <text class="time">{{formatTime(comment.createTime)}}</text>
           </view>
         <view v-else class="comment-item" v-for="(comment, index) in comments" :key="comment.id">
         <view style="display: flex;">
            <image class="comment-avatar" :src="comment.userAvatar || '/static/default-avatar.png'"></image>
            <view class="comment-content">
              <text class="nickname">{{comment.userNickname}}</text>
              <text class="content">{{comment.commentContent}}</text>
              <view style="position: relative;">
               <text class="time">{{formatTime(comment.createTime)}}</text>
               <text @click="openReply(comment)" class="reply-btu time">回复</text>
               <text v-if="!comment.hasThumbsUp" class="thumbs-up time iconfont" @click="thubmsUp(comment.id, index, null)">&#xe614;<text v-show="comment.thumbsUpNum > 0" class="thumbs-num">{{comment.thumbsUpNum}}</text></text>
               <text v-else class="thumbs-up time iconfont" @click="cancelThumbsUp(comment.id, index, null)">&#xe607;<text v-show="comment.thumbsUpNum > 0" class="thumbs-num">{{comment.thumbsUpNum}}</text></text>
              </view>
            </view>
         </view>
         <!-- 回复列表 -->
           <view class="reply-list" v-if="comment.replies && comment.replies.length > 0">
            <view class="reply-item" v-for="(reply, replyIndex) in comment.replies" :key="reply.id">
              <view class="reply-content">
               <view style="display: flex;">
                  <image class="comment-reply-avatar" :src="reply.replyUserAvatar || '/static/default-avatar.png'"></image>
                  <text class="nickname">{{reply.userNickname}}</text>
                  <text v-if="reply.replyUserId && reply.masterCommentId !== reply.replyId" class="reply-to"><text style="margin-right: 10rpx;font-size: 28rpx;" class="iconfont">&#xe666;</text>{{reply.replyUserNickname}}</text>
               </view>
               <text class="content">{{reply.commentContent}}</text>
               <view class="reply-footer">
                 <text class="time">{{formatTime(reply.createTime)}}</text>
                 <text @click="openReply(comment, reply)" class="reply-btu time">回复</text>
                 <text v-if="!reply.hasThumbsUp" class="thumbs-up time iconfont" @click="thubmsUp(reply.id, index, replyIndex)">&#xe614;<text v-show="reply.thumbsUpNum > 0" class="thumbs-num">{{reply.thumbsUpNum}}</text></text>
                 <text v-else class="thumbs-up time iconfont" @click="cancelThumbsUp(reply.id, index, replyIndex)">&#xe607;<text v-show="reply.thumbsUpNum > 0" class="thumbs-num">{{reply.thumbsUpNum}}</text></text>
               </view>
              </view>
            </view>
           </view>
           <view class="view-more-replies" v-if="comment.replyTotalCount > 0 && !comment.expandReply" @click="loadRepliesPage(comment, index)">
            <text class="line">——</text>展开{{comment.replyTotalCount}}条回复 ↓
           </view>
           <view class="reply-op" v-if="comment.replyTotalCount > replyCommentQuery.pageNumber * replyCommentQuery.pageSize && comment.expandReply">
              <view @click="loadNextPageReply(index)" class="reply-op-item"><text class="line">——</text>展开更多<text class="iconfont textSideIcon">&#xeb8d;</text></view>
              <view @click="retractReplyComment(index)" class="reply-op-item" style="margin-left: 50rpx;">收起<text class="iconfont textSideIcon">&#xeb9b;</text></view>
           </view>
           <view class="reply-op" v-else-if="comment.replyTotalCount <= replyCommentQuery.pageNumber * replyCommentQuery.pageSize && comment.expandReply">
              <view @click="retractReplyComment(index)" class="reply-op-item"><text class="line">——</text>收起<text class="iconfont textSideIcon">&#xeb9b;</text></view>
           </view>
         </view>
       </scroll-view>
       <view class="comment-input-area">
         <input
           class="comment-input"
           v-model="commentForm.commentContent"
           placeholder="写下你的评论..."
           placeholder-class="placeholder"
         />
         <button class="submit-btn" @click="submitComment">发送</button>
       </view>
        <input
         ref="commentInput"
         class="comment-input"
         v-model="commentForm.commentContent"
         :placeholder="commentForm.replyId ? `回复 @${commentForm.replyUserNickname}` : '写下你的评论...'"
         placeholder-class="placeholder"
        />
        <button class="submit-btn" @click="submitComment" :disabled="!commentForm.commentContent.trim()">发送</button>
      </view>
     </view>
   </uni-popup>
   
@@ -138,11 +230,34 @@
</template>
<script>
import { getRecommendVideos, savePlayRecord, subscribe, getVideoComments, addVideoComment } from "@/api/video.js";
import { getRecommendVideos, savePlayRecord, subscribe, getVideoComments, addVideoComment, thubmsUpComment, cancelThubmsUpComment } from "@/api/video.js";
import { changeCollect } from "@/api/collect.js";
import { saveShare } from "@/api/share.js";
import { silentLogin } from "@/api/connect.js";
import { getUserInfo } from "@/api/members";
import storage from "@/utils/storage.js";
export default {
  computed: {
       hasPlayTime() {
         return this.sliderFormatTime(this.progress > 0 ? this.duration * this.progress / 100 : 0);
       }
  },
  data() {
    return {
      currentImgIndex: 0, // 播放到第几张图--索引
      currentGoodsIndex: 0, // 播放到第几个商品--索引
      currentTime: 0,
      formartDuration: '',
      duration: 0,
      startX: 0,
      progress: 0, // 视频进度
      startProgress : 0, // 开始滑动时的进度
      barLeft: 0, // 进度条左边界位置
      barWidth: 0, // 进度条宽度
      isDragging: false, // 是否正在拖动
      processHidenTimer: null, // 进度条隐藏定时器
      showProcess: false, // 是否显示进度条
      videoNoMore: false, // 是否还有更多视频
      commentNoMore: false, // 是否还有更多评论
      commentQuery: {
         pageNumber: 1,
@@ -150,11 +265,21 @@
         videoId: '',
         masterCommentId: ''
      },
      replyCommentQuery: {
         pageNumber: 1,
         pageSize: 5,
         videoId: '',
         masterCommentId: ''
      },
      commentForm: { // 评论表单数据
         id: null,
         videoId: null,
         id: '',
         videoId: '',
         commentContent: '',
         replyId: null
         replyId: '',
         replyUserId: '',
         replyUserNickname: '',
         replyUserAvatar: '',
         masterCommentId: null
      },
      comments: [],            // 评论列表
      commentsTotal: 0,            // 评论总条数
@@ -178,12 +303,22 @@
      ],   // 视频列表数据
      videoContexts: [], // 视频上下文对象集合
      loading: false,  // 是否正在加载
      page: 1,         // 当前页码
      pageSize: 10     // 每页数量
      videoQuery: {
         pageNumber: 1,
         pageSize: 6,
         videoFrom: 'recommend'
      }
    }
  },
  onShow() {
     this.loadVideos()
     // const token = storage.getAccessToken();
     // if (! token) {
       //  this.wxSilentLogin(() => {
         //   this.loadVideos();
       //  })
     // } else {
     //      this.loadVideos();
     // }
     // 如果视频按下暂停后切换页面再回到页面时,只算暂停时间(因为暂停时间和离开页面时间是重复的,只算一个)
     if(this.startHidenTime !== 0 && this.currentVideoIsPlaying) {
        const duration = Date.now() - this.startHidenTime
@@ -194,13 +329,192 @@
     this.startHidenTime = Date.now()
  },
  onLoad() {
     this.loadVideos();
     const token = storage.getAccessToken();
     if (! token) {
        this.wxSilentLogin(() => {
           this.loadVideos();
        })
     } else {
      this.loadVideos();
     }
  },
  onReady() {
    // 初始化视频上下文
    this.initVideoContexts();
  },
  onShareAppMessage(e) {
   const userInfo = storage.getUserInfo();
   if(!userInfo) {
      console.log("未登录不能分享");
      return
   }
   const videoInfo = e.target.dataset.obj;
   // 保存分享记录
   const data = {
      shareType: 'video',
      refId: videoInfo.id,
      shareUser: userInfo.id
   }
   saveShare(data)
     return {
        title: videoInfo.title,
        path: `/pages/tabbar/index/home?videoId=${videoInfo.id}&userId=${userInfo.id}`,
        imageUrl: videoInfo.coverUrl
     }
  },
  methods: {
     // 静默登录
     wxSilentLogin(callback) {
        //获取code
        uni.login({
          success: (codeRes) => {
            if(codeRes.errMsg === "login:ok") {
            // 静默登录
            silentLogin({code: codeRes.code}).then(res => {
               storage.setAccessToken(res.data.data.accessToken);
               storage.setRefreshToken(res.data.data.refreshToken);
               //获取用户信息
               getUserInfo().then((user) => {
                 storage.setUserInfo(user.data.result);
                 storage.setHasLogin(true);
                 callback()
               });
            })
            } else {
              uni.showToast({
                title: "系统异常,请联系管理员!"
              })
            }
          },
        });
     },
     // 点击商品跳转
     jumpToPay(videoId) {
      uni.navigateTo({
         url: '/pages/video/video-goods-detail?videoId=' + videoId
      });
     },
     // 轮播图变化
     imgChange(e) {
        this.currentImgIndex = e.detail.current;
     },
     // 商品轮播图变化
     goodsChange(e) {
        this.currentGoodsIndex = e.detail.current;
     },
     // 获取进度条的位置和尺寸
     getBarRect() {
       const query = uni.createSelectorQuery().in(this);
       query.select('#progressBar').boundingClientRect(rect => {
         if (rect) {
           this.barLeft = rect.left;
           this.barWidth = rect.width;
         }
       }).exec();
     },
      // 跳转个人主页
      jumpToHomePage(authorId) {
         uni.navigateTo({
            url: "/pages/video/home-page?authorId=" + authorId
         })
      },
      // 取消点赞
      async cancelThumbsUp(id, commentIndex, replyIndex) {
         const data = {
            refId: id,
            thumbsUpType: 'video_comment'
         }
         cancelThubmsUpComment(data).then(res => {
            if(replyIndex != null) {
               this.comments[commentIndex].replies[replyIndex].hasThumbsUp = false;
               this.comments[commentIndex].replies[replyIndex].thumbsUpNum -= 1;
            } else {
               this.comments[commentIndex].hasThumbsUp = false;
               this.comments[commentIndex].thumbsUpNum -= 1;
            }
         })
      },
      // 评论点赞
      async thubmsUp(id, commentIndex, replyIndex) {
         const data = {
            refId: id,
            thumbsUpType: 'video_comment'
         }
         thubmsUpComment(data).then(res => {
            if(replyIndex != null) {
               this.comments[commentIndex].replies[replyIndex].hasThumbsUp = true;
               this.comments[commentIndex].replies[replyIndex].thumbsUpNum += 1;
            } else {
               this.comments[commentIndex].hasThumbsUp = true;
               this.comments[commentIndex].thumbsUpNum += 1;
            }
         })
      },
      // 加载下一页回复
      loadNextPageReply(index) {
         this.replyCommentQuery.pageNumber++;
         getVideoComments(this.replyCommentQuery).then(res => {
            this.comments[index].replies = [
              ...this.comments[index].replies,
              ...res.data.data.filter(
                (newItem) => !this.comments[index].replies.some((oldItem) => oldItem.id === newItem.id)
              ),
            ];
         })
      },
      // 收起回复
      retractReplyComment(index) {
         this.comments[index].expandReply = false;
         this.comments[index].replies = [];
      },
      // 加载回复
      loadRepliesPage(comment, index) {
         this.replyCommentQuery.pageNumber = 1;
         this.replyCommentQuery.masterCommentId = comment.id
          getVideoComments(this.replyCommentQuery).then(res => {
            this.comments[index].replies = res.data.data;
            this.comments[index].expandReply = true;
         })
      },
      resetCommentForm() {
         const videoId = this.commentForm.videoId;
         this.commentForm = { // 评论表单数据
            id: '',
            videoId: videoId,
            commentContent: '',
            replyId: '',
            replyUserId: '',
            replyUserNickname: '',
            replyUserAvatar: '',
            masterCommentId: null
         }
      },
       // 取消回复
       cancelReply() {
           this.resetCommentForm()
         },
      // 打开回复框
      openReply(comment, reply = null) {
        if(reply) {
         comment = reply
        }
        this.commentForm.masterCommentId = comment.masterCommentId ? comment.masterCommentId : comment.id;
        this.commentForm.replyId = comment.id;
        this.commentForm.replyUserId = comment.userId;
        this.commentForm.replyUserNickname = comment.userNickname;
        this.commentForm.replyUserAvatar = comment.userAvatar;
        // 自动聚焦输入框
        this.$nextTick(() => {
         const input = this.$refs.commentInput;
         if (input) input.focus();
        });
      },
      // 进度条时间格式化 (00:00)
      sliderFormatTime(seconds) {
        const mins = Math.floor(seconds / 60);
        const secs = Math.floor(seconds % 60);
        return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
      },
      // 格式化时间
       formatTime(time) {
         const date = new Date(time);
@@ -225,13 +539,20 @@
        // 发表评论
         addVideoComment(this.commentForm).then(res => {
           if(res.data.code === 200) {
              this.commentForm = {
                         id: null,
                         videoId: null,
                         commentContent: '',
                         replyId: null
              this.resetCommentForm()
              // 如果是评论别人的回复,那么就将这个发布到replies里面
              if(res.data.data.replyId) {
                 for (const [index, item] of this.comments.entries()) {
                   if (item.id === res.data.data.replyId) {
                     item.replies.unshift(res.data.data);
                     // this.loadRepliesPage(item, index)
                     break; // 跳出循环
                   }
                 }
              } else {
               this.comments.unshift(res.data.data);
              }
              this.comments.unshift(res.data.data);
              console.log("新增后",this.comments);
              uni.showToast({
                title: '评论成功'
@@ -257,12 +578,7 @@
        this.$refs.commentPopup.close()
         this.showCommentPopup = false;
         this.comments = [];
         this.commentForm = {
           id: null,
           videoId: null,
           commentContent: '',
           replyId: null
        }
         this.resetCommentForm()
        this.commentQuery.pageNumber = 1;
        this.commentNoMore = false;
       },
@@ -295,6 +611,7 @@
         this.$refs.commentPopup.open();
         this.commentLoading = true;
         this.commentQuery.videoId = item.id
         this.replyCommentQuery.videoId = item.id
        // 首次加载评论分页大小增加一倍,以产生滚动条,后续可触发
        this.commentQuery.pageSize *= 2;
        getVideoComments(this.commentQuery).then(res => {
@@ -343,22 +660,31 @@
    
    // 加载视频数据
    async loadVideos() {
      if (this.loading) return;
      if (this.loading || this.videoNoMore) return;
      this.loading = true;
      
     getRecommendVideos({pageNumber: this.page, pageSize: this.pageSize}).then(res => {
     getRecommendVideos(this.videoQuery).then(res => {
        console.log(res, "视频数据");
        if (this.page === 1) {
        if (this.videoQuery.pageNumber === 1) {
          this.videoList = res.data.data;
        } else {
          this.videoList = [...this.videoList, ...res.data.data];
         this.videoList = [
           ...this.videoList,
           ...res.data.data.filter(
             (newItem) => !this.videoList.some((oldItem) => oldItem.id === newItem.id)
           ),
         ];
        }
        this.page++;
        this.$nextTick(() => {
          this.initVideoContexts();
        });
        this.loading = false;
        if(res.data.data.length < this.videoQuery.pageSize) {
           this.videoNoMore = true;
           return;
        }
        this.videoQuery.pageNumber++;
     })
    },
    
@@ -412,6 +738,7 @@
    },
    // 单击屏幕:暂停或继续播放
   togglePlay(index) {
      console.log("单击视频", index, this.videoContexts);
      if(this.currentVideoIsPlaying) {
         this.videoContexts[index].pause();
      } else {
@@ -420,6 +747,8 @@
   },
    // 视频播放事件
    onPlay(id, index) {
      this.getBarRect()
      this.progress = 0
      console.log(id, index, "触发播放");
      if(index === this.currentIndex) {
         this.currentVideoIsPlaying = true;
@@ -449,7 +778,6 @@
      }
     this.startPauseTime = Date.now()
    },
    // 视频结束事件
    onEnded(index) {
      // this.currentVideoIsPlaying = false;
@@ -457,9 +785,66 @@
   
   // 记录播放时长
   onTimeUpdate(e) {
      this.playRecord.playAt = e.detail.currentTime
      this.playRecord.playAt = e.detail.currentTime;
      this.currentTime = e.detail.currentTime;
      this.progress = (e.detail.currentTime / this.duration) * 100
   },
   // 触摸开始
   handleTouchStart(e) {
     this.isDragging = true;
     this.showProcess = true;
     this.startProgress = this.progress; // 记录开始时的进度
     this.startX = e.touches[0].pageX;
     console.log("记录开始时的进度", this.startProgress);
     this.videoContexts[this.currentIndex].pause()
     // this.updateProgress(e);
   },
   
   // 触摸移动
   handleTouchMove(e) {
     if (!this.isDragging || !this.barWidth) return;
     clearTimeout(this.processHidenTimer)
     this.videoContexts[this.currentIndex].pause()
     this.updateProgress(e);
   },
   // 触摸结束
   handleTouchEnd() {
     this.isDragging = false;
     console.log("滑动结束", this.duration * this.progress);
     this.videoContexts[this.currentIndex].seek(this.duration * this.progress / 100)
     this.videoContexts[this.currentIndex].play()
     this.processHidenTimer = setTimeout(() => {
        this.showProcess = false;
      }, 1000);
   },
   // 更新进度
   updateProgress(e) {
      // 获取当前触摸点X坐标
      const currentX = e.touches[0].pageX;
      // 计算滑动距离(像素)
      const deltaX = currentX - this.startX;
      // 将像素距离转换为进度增量
      const deltaProgress = (deltaX / this.barWidth) * 100;
      console.log("进度增量", deltaProgress);
      // 计算新进度 = 开始时的进度 + 滑动增量
      let newProgress = this.startProgress + deltaProgress;
      // 限制范围在0-100之间
      newProgress = Math.max(0, Math.min(100, newProgress));
      this.progress = newProgress;
   },
   // 获取视频总时长
   onLoadedMetadata(e) {
     this.duration = e.detail.duration;
     this.formartDuration = this.sliderFormatTime(this.duration);
     console.log("视频总时长", this.duration);
   },
   // 保存播放记录
   async savePlayRecord() {
      console.log(Date.now(), this.playRecord.startPlayTime, this.totalHidenTime);
@@ -495,7 +880,7 @@
   
   .video-swiper {
     width: 100%;
     height: 100%;
     height: calc(100% - 50px);
   }
   
   .video-item {
@@ -591,6 +976,7 @@
   }
   .goods-link {
     position: relative;
     width: 450rpx;
     margin: 20rpx 0;
     padding: 12rpx;
     background-color: rgba(255, 255, 255, 0.9);
@@ -599,6 +985,7 @@
   }
   
   .goods-container {
     width: 100%;
     display: flex;
     align-items: center;
   }
@@ -621,11 +1008,13 @@
     font-size: 28rpx;
     color: #333;
     font-weight: bold;
     display: -webkit-box;
     -webkit-line-clamp: 2;
     -webkit-box-orient: vertical;
     overflow: hidden;
     margin-bottom: 8rpx;
     width: 280rpx; /* 需要指定宽度 */
     overflow: hidden;
     white-space: nowrap;
     text-overflow: ellipsis;
   }
   
   .price-section {
@@ -642,7 +1031,7 @@
   }
   
   .original-price {
     font-size: 24rpx;
     font-size: 28rpx;
     color: #999;
     text-decoration: line-through;
   }
@@ -655,7 +1044,7 @@
   .buy-button {
     background: linear-gradient(to right, #ff5a5f, #ff2e4d);
     color: white;
     padding: 10rpx 24rpx;
     padding: 10rpx 28rpx;
     border-radius: 20rpx;
     font-size: 26rpx;
     font-weight: bold;
@@ -697,14 +1086,21 @@
   .comment-item {
     display: flex;
     padding: 10rpx 0;
     flex-direction: column;
     padding: 10rpx 0 20rpx 0;
   }
   .avatar {
     width: 80rpx;
     height: 80rpx;
   .comment-avatar {
     width: 70rpx;
     height: 70rpx;
     border-radius: 50%;
     margin-right: 20rpx;
     margin-right: 10rpx;
   }
   .comment-reply-avatar {
      width: 40rpx;
      height: 40rpx;
      border-radius: 50%;
      margin-right: 10rpx;
   }
   .comment-content {
@@ -712,21 +1108,21 @@
   }
   .nickname {
     font-size: 24rpx;
     font-size: 28rpx;
     color: #666;
     display: block;
     margin-bottom: 10rpx;
   }
   .content {
     font-size: 24rpx;
     font-size: 28rpx;
     color: #333;
     display: block;
     margin-bottom: 10rpx;
   }
   .time {
     font-size: 24rpx;
     font-size: 28rpx;
     color: #999;
   }
@@ -766,4 +1162,140 @@
     text-align: center;
     color: #999;
   }
   .reply-list {
     margin-top: 20rpx;
     padding-left: 80rpx;
   }
   .reply-op {
      margin-top: 10rpx;
      padding-left: 80rpx;
      display: flex;
      font-size: 28rpx;
      color: #333;
   }
   .reply-op-item {
      display: flex;
      align-items: center;
      height: 40rpx;
   }
   .reply-item {
     display: flex;
     margin-bottom: 20rpx;
   }
   .reply-content {
     flex: 1;
   }
   .reply-to {
     color: #576b95;
     margin: 0 10rpx;
     font-size: 28rpx;
   }
   .reply-title {
     display: flex;
     align-items: center;
     font-size: 28rpx;
     color: #333;
   }
   .cancel-reply {
     margin-left: 20rpx;
     color: #576b95;
     font-size: 28rpx;
     padding: 6rpx 12rpx;
     background: #f5f5f5;
     border-radius: 20rpx;
   }
   .view-more-replies {
     color: #576b95;
     font-size: 28rpx;
     padding: 10rpx 0;
     padding-left: 80rpx;
   }
   .comment-footer, .reply-footer {
     display: flex;
     align-items: center;
     font-size: 28rpx;
     color: #999;
   }
   .reply-btu {
      margin-left: 30rpx;
   }
   .thumbs-up {
      position: absolute;
      right: 20rpx;
      font-size: 32rpx;
      width: 120rpx;
   }
   .textSideIcon {
      font-size: 36rpx;
      margin-left: 5rpx;
   }
   .line {
      margin-right: 10rpx;
      color: #cccccc;
   }
   .thumbs-num {
      margin-left: 4rpx;
   }
   .container {
     display: flex;
     flex-direction: column;
     align-items: center;
     position: absolute;
     bottom: 0;
     width: 100%;
   }
   .progress-bar {
     position: relative;
     width: 100%;
     height: 16px;
     background-color: #eee;
     overflow: hidden;
   }
   .progress-fill {
     position: absolute;
     left: 0;
     top: 0;
     height: 100%;
     background-color: lightgray;
     transition: width 0.1s;
   }
   .process-warp {
      width: 100%;
      display: flex;
      flex-direction: column;
      align-items: center;
   }
   .progress-text {
     margin-top: 10px;
     font-size: 14px;
     color: #666;
   }
   .swiper-box {
     width: 100%;
     height: 1400rpx;
   }
   .swiper-item {
     display: flex;
     justify-content: center;
     align-items: center;
     width: 100%;
     height: 100%;
   }
   .custom-share-btn {
     font-size: unset;
     background: none;
     padding: 0;
     margin: 0;
     line-height: normal;
     border: none;
   }
   .custom-share-btn::after {
     border: none;
   }
</style>