绿满眶商城微信小程序-uniapp
zxl
2025-07-30 61032da9f6f840c9c96af090d1810bc7a0734f4b
pages/tabbar/index/home.vue
@@ -14,7 +14,7 @@
    >
      <swiper-item
      v-for="(item, index) in videoList"
      :key="item.id"
      :key="item.updateKey"
      @touchstart="handleSwiperStart"
      @touchmove="handleSwiperMove"
      @touchend="handleSwiperEnd(item)"
@@ -26,7 +26,7 @@
            @click="togglePlay(index)"
            v-show="!currentVideoIsPlaying"
           >
            <image src="/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image>
            <image src="/pages/subComponents/static/video/play.png" style="width: 45px;height: 45px" mode="aspectFit"></image>
           </view>
           <video
            v-if="index >= currentIndex - videoLiveOffset && index <= currentIndex + videoLiveOffset"
@@ -120,21 +120,23 @@
        <!-- 视频信息层 -->
        <view class="video-info" :style="{bottom: marginBottom + 20 + 'px'}">
        <view>
           <text class="video-author" @click="jumpToSearch">@{{item.authorName}}</text>
        <view style="width: 100%; position: relative;">
           <text class="video-author">@{{item.authorName}}</text>
           <text class="iconfont" @click="jumpToSearch" style="position: absolute;right: 45px;">&#xe64e;</text>
        </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.id">#{{tag.tagName}}</text>
        </view>
        </view>
       <!-- 右侧互动按钮 -->
       <view class="action-buttons">
         <view class="avatar-container">
            <image class="avatar" @click="jumpToHomePage(item.authorId)" :src="item.authorAvatar" mode="aspectFill"></image>
            <image class="avatar" @click="jumpToHomePage(item.authorId)" @touchend.stop :src="item.authorAvatar" mode="aspectFill"></image>
            <!-- 关注图标 - 使用绝对定位 -->
            <view v-if="!item.subscribeThisAuthor" class="follow-icon" @click="subscribeAuth(index, item.authorId)">
            <view v-if="!item.subscribeThisAuthor" class="follow-icon" @click="subscribeAuth(index, item.authorId)" @touchend.stop>
             <text class="iconfont">&#xe629;</text>
            </view>
         </view>
@@ -187,7 +189,7 @@
         <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="nickname">{{comment.userNickname}} <text v-if="userId===comment.userId">(我)</text> </text>
              <text class="content">{{comment.commentContent}}</text>
              <view style="position: relative;">
               <text class="time">{{formatTime(comment.createTime)}}</text>
@@ -203,8 +205,8 @@
              <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>
                  <text class="nickname">{{reply.userNickname}}<text v-if="userId===comment.userId">(我)</text></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 v-if="userId===comment.userId">(我)</text></text>
               </view>
               <text class="content">{{reply.commentContent}}</text>
               <view class="reply-footer">
@@ -256,6 +258,7 @@
   thubmsUpComment, 
   cancelThubmsUpComment,
   changeThumbsUp,
   getGoodsSimilarlyVideos
} from "@/api/video.js";
import { changeCollect } from "@/api/collect.js";
import { saveShare, saveShareClickRecord } from "@/api/share.js";
@@ -273,6 +276,7 @@
  },
  data() {
    return {
      userId :'',
      currentImgIndex: 0, // 播放到第几张图--索引
      currentGoodsIndex: 0, // 播放到第几个商品--索引
      currentTime: 0,
@@ -341,10 +345,24 @@
         pageSize: 10,
         videoFrom: 'recommend'
      },
      goodsSimilarlyQuery: { // 相似视频查询
         pageNumber: 1,
         pageSize: 10,
         videoFrom: 'goodsSimilarly',
         goodsIds: [],
         currentVideoId: ''
      },
      similarlyVideoList: [], // 相似视频
      similarlyNomore: false, // 是否还有更多相似视频
      similaryVideoIndex: 0, // 相似视频的播放位置
      similarlyLoading: false, // 相似视频加载
      marginBottom: 0 // 底部安全区域
    }
  },
  onShow() {
     if(!this.userId){
        this.getUserId()
     }
     // const token = storage.getAccessToken();
     // if (! token) {
       //  this.wxSilentLogin(() => {
@@ -353,6 +371,12 @@
     // } else {
     //      this.loadVideos();
     // }
     if (this.videoList.length < 1) {
        this.loading = false;
        this.videoNoMore = false;
        console.log('触发数据加载')
        this.loadVideos();
     }
     // 如果视频按下暂停后切换页面再回到页面时,只算暂停时间(因为暂停时间和离开页面时间是重复的,只算一个)
     if(this.startHidenTime !== 0 && this.currentVideoIsPlaying) {
        const duration = Date.now() - this.startHidenTime
@@ -363,19 +387,44 @@
     this.startHidenTime = Date.now()
  },
  onLoad(option) {
     console.log('-----------分享出的数据---------->',option)
     //处理扫码出来的视频
     this.marginBottom = uni.getSystemInfoSync().safeAreaInsets.bottom
           // 检查是否存在q参数
         let queryParam = this.videoQuery;
           if (option.q) {
             // 双重解码:微信对URL进行了两次编码
             const decodedUrl = decodeURIComponent(decodeURIComponent(option.q));
             console.log('原始URL:', decodedUrl);
             // 解析URL中的查询参数
             const params = this.parseUrlParams(decodedUrl);
             const shareType = params.shareType;
             const videoId = params.videoId;
             queryParam.videoId = videoId
             console.log('解析参数:', { shareType, videoId });
           }
     const token = storage.getAccessToken();
     if (! token) {
        this.wxSilentLogin(() => {
           this.loadVideos();
           // 判断是不是点击分享链接进来的
           if (option.userId && option.videoId) {
              queryParam.videoId = option.videoId
              // 保存分享点击记录
              saveShareClickRecord({refId: option.videoId, shareUserId: option.userId})
           }
           console.log('------------------------>',queryParam)
           this.loadVideos(queryParam);
        })
     } else {
      this.loadVideos();
        if (option.userId && option.videoId) {
           queryParam.videoId = option.videoId
                      // 保存分享点击记录
            saveShareClickRecord({refId: option.videoId, shareUserId: option.userId})
        }
        console.log('------------------------2>',queryParam)
      this.loadVideos(queryParam);
     }
  },
  onShareAppMessage(e) {
@@ -395,10 +444,60 @@
     return {
        title: videoInfo.title,
        path: `/pages/tabbar/index/home?videoId=${videoInfo.id}&userId=${userInfo.id}`,
        imageUrl: videoInfo.coverUrl
     }
  },
  methods: {
  methods: {
     getUserId(){
        const {id} = uni.getStorageSync('user_info_obj_dev')
        this.userId = id;
     },
     // 解析URL参数
    parseUrlParams(url) {
      const params = {};
      // 处理可能存在的hash(如果有的话)
      const cleanUrl = url.split('#')[0];
      const queryStr = cleanUrl.split('?')[1] || '';
      queryStr.split('&').forEach(pair => {
        const [key, value] = pair.split('=');
        if (key) {
          // 如果值存在,则解码,否则设为空字符串
          params[key] = value ? decodeURIComponent(value) : '';
        }
      });
      return params;
    },
     // 查询当前视频的关联视频(挂了同一商品的)
     async getGoodsSimilarly() {
        if (this.similarlyLoading || this.similarlyNomore) return Promise.resolve();;
        const video = this.videoList[this.currentIndex];
        if (video.goodsList && video.goodsList.length > 0) {
           this.goodsSimilarlyQuery.goodsIds = video.goodsList.map(goods => goods.goodsId);
           this.goodsSimilarlyQuery.currentVideoId = video.id;
           if (this.similarlyVideoList.length < 1) {
              this.similarlyVideoList.push(video); // 确保原视频是横向视频的第一个元素
           }
           this.similarlyLoading = true;
           return getGoodsSimilarlyVideos(this.goodsSimilarlyQuery).then(res => {
                      this.similarlyVideoList = [
                        ...this.similarlyVideoList,
                        ...res.data.data.filter(
                         (newItem) => !this.similarlyVideoList.some((oldItem) => oldItem.id === newItem.id)
                        ),
                      ];
                      this.similarlyLoading = false;
                      if(res.data.data.length < this.goodsSimilarlyQuery.pageSize) {
                         this.similarlyNomore = true;
                         return;
                      }
                      this.goodsSimilarlyQuery.pageNumber++;
           })
        }
     },
     // 跳转到搜索页
     jumpToSearch() {
        uni.navigateTo({
           url: '/pages/video/video-search'
@@ -467,6 +566,7 @@
     },
      // 跳转个人主页
      jumpToHomePage(authorId) {
         console.log("作者id", authorId);
         uni.navigateTo({
            url: "/pages/video/home-page?authorId=" + authorId
         })
@@ -670,6 +770,7 @@
        getVideoComments(this.commentQuery).then(res => {
           this.commentsTotal = res.data.total;
           this.comments = res.data.data;
           console.log('------------------------>',this.comments)
           this.commentQuery.pageNumber += 2;
           this.commentQuery.pageSize /= 2;
        }).catch(() => {
@@ -705,21 +806,56 @@
     },
    // 加载视频数据
    async loadVideos() {
    async loadVideos(param) {
      if (this.loading || this.videoNoMore) return;
      this.loading = true;
      if(param){
         getRecommendVideos(param).then(res => {
                 // 新增一个字段用于循环时的key
                 const data = res.data.data.map(item => {
                    return {
                       ...item,
                       updateKey: item.id
                    }
                 })
                 if (this.videoQuery.pageNumber === 1) {
                   this.videoList = data;
                 } else {
                  this.videoList = [
                    ...this.videoList,
                    ...data.filter(
                      (newItem) => !this.videoList.some((oldItem) => oldItem.id === newItem.id)
                    ),
                  ];
                 }
                 this.loading = false;
                 if(res.data.data.length < this.videoQuery.pageSize) {
                    this.videoNoMore = true;
                    return;
                 }
                 this.videoQuery.pageNumber++;
         })
      }else{
     getRecommendVideos(this.videoQuery).then(res => {
        console.log(res, "视频数据");
        // 新增一个字段用于循环时的key
        const data = res.data.data.map(item => {
           return {
              ...item,
              updateKey: item.id
           }
        })
        if (this.videoQuery.pageNumber === 1) {
          this.videoList = res.data.data;
          this.videoList = data;
        } else {
         this.videoList = [
           ...this.videoList,
           ...res.data.data.filter(
           ...data.filter(
             (newItem) => !this.videoList.some((oldItem) => oldItem.id === newItem.id)
           ),
         ];
        }
        this.loading = false;
        if(res.data.data.length < this.videoQuery.pageSize) {
@@ -729,6 +865,7 @@
        this.videoQuery.pageNumber++;
     })
     }
    },
    // 滑动切换视频
@@ -757,10 +894,28 @@
      // 播放当前视频
      const videoContext1 = uni.createVideoContext(`video${this.currentIndex}`, this);
      videoContext1.play()
      // 下滑时,需要将上一个视频重置为原始视频(如果横向滑动了相关视频)
      if (this.similaryVideoIndex !== 0) {
         this.videoList[oldIndex] = this.similarlyVideoList[0]
      }
      this.similarlyVideoList = [];
      this.similaryVideoIndex = 0;
      this.similarlyNomore = false;
      this.similarlyLoading = false;
      this.goodsSimilarlyQuery = {
         pageNumber: 1,
         pageSize: 6,
         videoFrom: 'goodsSimilarly',
         goodsIds: [],
         currentVideoId: ''
      }
      // 如果剩余视频不足,触发请求获取更多视频
      if (this.videoList.length - 1 < this.currentIndex + this.videoLiveOffset) {
         this.loadVideos()
      }
    },
   // 开始触摸
@@ -775,7 +930,7 @@
       this.touchXY.endY = e.touches[0].pageY
   },
   // 结束触摸
   handleSwiperEnd(item) {
   async handleSwiperEnd(item) {
      // 防止滑动滚动条也触发跳转
      if (this.showProcess) {
         return
@@ -787,11 +942,37 @@
       if (Math.abs(diffX) > Math.abs(diffY)) {
         if (diffX > 0) {
           console.log('右滑')
         if (item.goodsList && item.goodsList.length > 0) {
         if (this.similaryVideoIndex !== 0) {
            // 如果滑动了横向视频,那么右滑就做视频切换而不是跳转商品页
            // 切换下一个视频
            const oldIndex = this.similaryVideoIndex;
            this.similaryVideoIndex = Math.max(this.similaryVideoIndex - 1, 0);
            if (this.similaryVideoIndex < oldIndex) {
               // 把竖向视频的当前播放位置替换为横向视频的当前索引元素
               const video = this.similarlyVideoList[this.similaryVideoIndex];
               video["updateKey"] = video.id + this.similaryVideoIndex
               this.videoList.splice(this.currentIndex, 1, video);
               // this.videoList[this.currentIndex] = video
            }
         }
         else if (item.goodsList && item.goodsList.length > 0) {
            this.jumpToPay(item.id)
         }
         } else {
           console.log('左滑')
         if (this.similarlyVideoList.length < 1 || this.similarlyVideoList.length - this.similaryVideoIndex - 1 <= 3) {
            // 相关视频为空或者剩余视频不足,触发加载相关视频
            await this.getGoodsSimilarly()
         }
         // 切换下一个视频
         const oldIndex = this.similaryVideoIndex;
         this.similaryVideoIndex = Math.min(this.similaryVideoIndex + 1, this.similarlyVideoList.length - 1);
         if (this.similaryVideoIndex > oldIndex) {
            // 把竖向视频的当前播放位置替换为横向视频的当前索引元素
            const video = this.similarlyVideoList[this.similaryVideoIndex];
            video["updateKey"] = video.id + this.similaryVideoIndex
            this.videoList.splice(this.currentIndex, 1, video);
         }
         }
       }
       // 重置坐标
@@ -1022,7 +1203,7 @@
   }
   .video-info {
     width: 70%;
     width: 100%;
     position: absolute;
     bottom: 20px;
     left: 20px;