绿满眶商城微信小程序-uniapp
xiangpei
5 天以前 4e9d7c0e363d313a273700865afb8b0d665e6c69
视频相关页面优化、功能bug
5个文件已修改
1个文件已删除
489 ■■■■■ 已修改文件
components/dropdown-menu.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabbar/index/home.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabbar/index/home1.vue 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/video/home-page.vue 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/video/video-play.vue 297 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/dropdown-menu.vue
@@ -149,7 +149,7 @@
.dropdown-menu {
  position: absolute;
  left: 0;
  left: -50rpx;
  display: inline-block;
  white-space: nowrap;
  background-color: #fff;
pages.json
@@ -26,12 +26,6 @@
                "navigationStyle": "custom" // 隐藏顶部导航栏
            }
        },
        // {
        //     "path": "pages/tabbar/index/home1",
        //     "style": {
        //         "navigationBarTitleText": ""
        //     }
        // },
        {
            "path": "pages/tabbar/home/index",
            "style": {
pages/tabbar/index/home.vue
@@ -916,7 +916,7 @@
    .video-info {
      width: 70%;
      position: absolute;
      bottom: 70px;
      bottom: 20px;
      left: 20px;
      color: #f8f8f8;
      z-index: 10;
pages/tabbar/index/home1.vue
File was deleted
pages/video/home-page.vue
@@ -61,12 +61,13 @@
        
        <!-- 视频列表 -->
        <scroll-view class="video-list" scroll-y :show-scrollbar="false" @scrolltolower="getPage" v-show="currentTab === 'works' && videoList.length > 0">
            <view class="video-container">
                <view
                  class="video-item" 
                  v-for="(item, index) in videoList" 
                  :key="item.id"
                >
                  <image class="video-cover" @click="playAuthorVideo(index)" :src="item.coverUrl" mode="aspectFill"></image>
                  <image class="video-cover" @click="playAuthorVideo(index)" :src="item.videoContentType === 'video' ? item.coverUrl : item.imgs[0]" mode="aspectFill"></image>
                  <view class="video-info">
                    <view class="video-stats">
                      <view class="stat">
@@ -84,6 +85,7 @@
                    </view>
                  </view>
            </view>
            </view>
        </scroll-view>
        <scroll-view class="video-list" scroll-y :show-scrollbar="false" @scrolltolower="getPage" v-show="currentTab === 'likes' && collectVideoList.length > 0">
            <view class="video-container">
@@ -93,7 +95,7 @@
                  :key="item.id"
                  @click="playCollectVideo(index)"
                >
                  <image class="video-cover" :src="item.coverUrl" mode="aspectFill"></image>
                  <image class="video-cover" :src="item.videoContentType === 'video' ? item.coverUrl : item.imgs[0]" mode="aspectFill"></image>
                  <view class="video-info">
                    <view class="video-stats">
                      <view class="stat">
@@ -301,7 +303,7 @@
      });
    },
    // 播放收藏视频
    playAuthorVideo(index) {
    playCollectVideo(index) {
      const playInfo = {
          videoList: this.collectVideoList,
          nomore: this.nomoreCollectVideo,
@@ -460,16 +462,21 @@
}
.video-list {
  width: calc(100% - 20rpx);
  width: 100%;
  padding: 0 10rpx;
  height: calc(100vh - 554rpx);
  background-color: #fff;
}
.video-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
.video-item {
  width: 50%;
  padding: 10rpx;
  box-sizing: border-box;
  width: 49%;
  margin-bottom: 20rpx;
  position: relative;
}
@@ -481,15 +488,12 @@
}
.video-info {
  display: flex;
  height: 60rpx;
  align-items: center;
  font-size: 24rpx;
  width: 100%;
  padding-right: 20rpx;
  box-sizing: border-box;
  position: absolute;
  bottom: 20rpx;
  bottom: 10rpx;
  left: 0;
  right: 0;
  padding: 0 10rpx;
  box-sizing: border-box;
}
.video-title {
@@ -569,8 +573,4 @@
  }
}
.video-container {
    display: flex;
    flex-wrap: wrap
}
</style>
pages/video/video-play.vue
@@ -9,6 +9,7 @@
      @change="onSwiperChange"
    >
      <swiper-item v-for="(item, index) in videoList" :key="item.id">
          <view style="width: 100%;height: 100%;" v-if="item.videoContentType === 'video'">
        <!-- 播放按钮(仅当视频暂停时显示) -->
        <view 
          class="play-icon" 
@@ -25,36 +26,81 @@
          :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>
          <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">
                <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="item.goods.imageUrl" mode="aspectFill"></image>
                      <image class="goods-image" :src="goods.thumbnail" mode="aspectFill"></image>
                
                <!-- 商品信息 -->
                <view class="goods-info">
                  <text class="goods-name">{{item.goods.name}}</text>
                        <text class="goods-name">{{goods.goodsName}}</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>
                          <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>
        
@@ -87,6 +133,12 @@
         <view class="action-item" @click="showComments(item)">
            <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>
        
@@ -178,9 +230,29 @@
<script>
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 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: {
@@ -253,6 +325,7 @@
      const playInfo = uni.getStorageSync("playInfo", playInfo);
      if(playInfo) {
          this.videoList = playInfo.videoList;
          console.log("拿到数据了",playInfo);
          this.videoQuery.pageNumber = playInfo.pageNumber;
          this.videoNoMore = playInfo.nomore;
          this.videoQuery.authorId = option.authorId;
@@ -267,7 +340,51 @@
    // 初始化视频上下文
    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: {
      // 点击商品跳转
      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({
@@ -364,6 +481,12 @@
            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) {
@@ -562,6 +685,67 @@
        }
    },
    
    // 获取进度条的位置和尺寸
    getBarRect() {
      const query = uni.createSelectorQuery().in(this);
      query.select('#progressBar').boundingClientRect(rect => {
        if (rect) {
          this.barLeft = rect.left;
          this.barWidth = rect.width;
        }
      }).exec();
    },
    // 触摸开始
    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;
    },
    // 收藏/取消收藏
    toggleCollect(item, index) {
      let data = {
@@ -594,9 +778,15 @@
    },
    // 视频播放事件
    onPlay(id, index) {
        console.log(id, index, "触发播放");
        this.getBarRect()
        this.progress = 0
        if(index === this.currentIndex) {
            this.currentVideoIsPlaying = true;
            if(! this.duration) {
                // 设置当前播放视频的总时长
                this.duration = this.videoList[this.currentIndex].videoDuration;
                this.formartDuration = this.sliderFormatTime(this.duration);
            }
        } else {
            this.currentVideoIsPlaying = false;
            return
@@ -632,8 +822,15 @@
    // 记录播放时长
    onTimeUpdate(e) {
        this.playRecord.playAt = e.detail.currentTime
        this.currentTime = e.detail.currentTime;
        this.progress = (e.detail.currentTime / this.duration) * 100
    },
    // 获取视频总时长
    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);
@@ -669,7 +866,7 @@
    
    .video-swiper {
      width: 100%;
      height: 100%;
      height: calc(100% - 20rpx);
    }
    
    .video-item {
@@ -691,7 +888,7 @@
    .video-info {
      width: 70%;
      position: absolute;
      bottom: 70px;
      bottom: 20px;
      left: 20px;
      color: #f8f8f8;
      z-index: 10;
@@ -765,6 +962,7 @@
    }
    .goods-link {
      position: relative;
      width: 450rpx;
      margin: 20rpx 0;
      padding: 12rpx;
      background-color: rgba(255, 255, 255, 0.9);
@@ -773,6 +971,7 @@
    }
    
    .goods-container {
      width: 100%;
      display: flex;
      align-items: center;
    }
@@ -795,11 +994,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 {
@@ -1025,4 +1226,62 @@
    .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: 1200rpx;
    }
    .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>