vue3 上传视频 第一帧放在背景色上

<template>
  <div class="rightInfo">
    <van-image-preview v-model:show="show" :startPosition="startPosition" :images="picUrl" @change="onChange" />
    <van-overlay v-model:show="showDialog" @click="showDialog = false" :lock-scroll="false">
      <div class="block">
        <div class="content">
          <div ref="traceTitle">
            <p class="traceTitle">1111111</p>
          </div>
          <div class="content-track">
            <logistics-track :data-source="trackList"></logistics-track>
          </div>
          <div class="opacity"></div>
        </div>
        <div class="cancel" @click="showDialog = false">我知道了</div>
      </div>
    </van-overlay>
    <div v-if="dataList" class="info">
      <div class="timeBar">
        <div class="time">{{ dataList.createTime }}</div>
        <div class="nickname">{{ type ? dataList.registrationNetworkName : dataList.replyNetworkName }}</div>
      </div>
      <!-- 详情部分 -->
      <div v-if="type" class="mainInfo">
        <div class="infoLine">
          <span class="infoTitle">详情</span>
          <span class="trace" @click="openTrack">111111</span>
        </div>
        <div class="infoLine">
          <span class="infoName">单号: </span>
          <span class="infoValue">{{ dataList.waybillNo }}</span>
        </div>
        <div class="infoLine">
          <span class="infoName">2222: </span>
          <span class="infoValue">{{ dataList.receiveNetworkName }}</span>
          <span></span>
        </div>
        <div class="infoLine">
          <span class="infoName">类型1: </span>
          <span class="infoValue">{{ dataList.probleTypeSubjectName }}</span>
          <span></span>
        </div>
        <div class="infoLine">
          <span class="infoName">类型2: </span>
          <span class="infoValue">{{ dataList.secondLevelTypeName }}</span>
          <span></span>
        </div>
        <div class="infoLine">
          <span class="infoName">问题件状态: </span>
          <span class="infoValue">{{ dataList.problePieceStatus === 1 ? '待处理' : dataList.problePieceStatus === 2 ? '处理中'
              : '已处理'
          }}</span>
          <span></span>
        </div>
        <div v-if="dataList.urls && dataList.urls.length" class="infoLineImg">
          <div class="infoName">图片: </div>
          <van-swipe class="extra" indicator-color="white">
            <van-swipe-item class="extra-swiper" v-for="(imgItem, imgIndex) in dataList.urls" :key="imgIndex">
              <img :src="imgItem" @click="reviewPic(dataList.urls, imgIndex)">
            </van-swipe-item>
            <!-- swiper指示器 -->
            <template #indicator="{ active, total }">
              <div class="extra-indicator">{{ active + 1 }}/{{ total }}</div>
            </template>
          </van-swipe>
        </div>
        <div v-if="dataList.videoList && dataList.videoList.length" class="infoLineImg infoLineVideo">
          <div class="infoName">视频: </div>
          <van-swipe class="extra" id="extra" @change="swiperChange">
            <van-swipe-item class="extra-swiper" v-for="(videoItem, videoIndex) in dataList.videoList"
              :key="videoIndex">
              <video :id="'video' + videoIndex" crossOrigin="anonymous" 
                :src="videoItem.url" :controls="showControls" style="object-fit:cover;">
              </video>
              <!-- 添加遮罩 避免video滑动无法触发轮播 -->
              <div v-if="!showControls" class="play" @click="playSwiperVideo(videoIndex)">
                <img class="btn" src="@/assets/img/play.png" @click="clickPlayVideo(videoItem.url)" />
              </div>
            </van-swipe-item>
            <!-- 自定义swiper指示器 -->
            <template #indicator="{ active, total }">
              <div class="extra-indicator">{{ active + 1 }}/{{ total }}</div>
            </template>
          </van-swipe>
        </div>
      </div>
      <!-- 内容部分 -->
      <div v-else class="mainInfo">
        <div class="infoLine">
          <div class="infoValue">{{ dataList.replyContent }}</div>
        </div>
        <div class="infoLine" v-if="dataList.urls && dataList.urls.length">
          <div class="infoLineImg">
            <van-swipe class="extra" indicator-color="white">
              <van-swipe-item class="extra-swiper" v-for="(imgItem, imgIndex) in dataList.urls" :key="imgIndex">
                <img :src="imgItem" @click="reviewPic(dataList.urls, imgIndex)">
              </van-swipe-item>
              <!-- swiper指示器 -->
              <template #indicator="{ active, total }">
                <div class="extra-indicator">{{ active + 1 }}/{{ total }}</div>
              </template>
            </van-swipe>
          </div>
        </div>
      </div>
    </div>
    <div class="avatar">
      <img src="@/assets/img/default.png">
    </div>
  </div>
</template>
<script lang="ts">
import { CommonResModel } from '@/api/model/commonModel'
import { getOrderTrackDetailRes, getOrderTrackRes } from '@/api/model/workOrderManageModel'
import { playVideo } from '@/utils/nativeAPI'
import AjaxWorkOrderManageService from '@/api/workOrderManage'
import { defineComponent, ref } from 'vue'
import LogisticsTrack from "@/components/LogisticsTrack/src/LogisticsTrack.vue"
export default defineComponent({
  components: { LogisticsTrack },
  props: {
    dataList: {
      default: () => {
        return {}
      },
      type: Object,
    },
    type: {
      type: Boolean,
      default: false
    }
  },
  setup(props) {
    const { dataList } = props
    // 判断是否是视频
    const showDialog = ref<boolean>(false)
    // 查看物流轨迹
    const trackList = ref<getOrderTrackDetailRes[]>([])
    function openTrack() {
      AjaxWorkOrderManageService.getOrderTrack({
        waybillNos: dataList.waybillNo
      })
        .then((res: CommonResModel<getOrderTrackRes[]>) => {
          if (res.code === 1) {
            trackList.value = res.data ? res.data[0].details : []
            showDialog.value = true
            // const trackNetworkIds: any = []
            // trackList.value.map(c => {
            //   trackNetworkIds.push(c.scanNetworkId)
            // })
          }
        })
        .catch((err) => {

        })
    }

    const index = ref<number>(0)
    const show = ref<boolean>(false)

    const picUrl = ref<Array<string>>([''])
    const startPosition = ref<number>(0)
    const reviewPic = (value: string[], num: number) => {
      show.value = true
      picUrl.value = value
      startPosition.value = num
    }

    const onChange = (newIndex) => {
      index.value = newIndex
    }

    const showControls = ref<boolean>(false)
    function playSwiperVideo(e) {
      const videoRef: any = document.getElementById(`video${e}`)
      videoRef.play()
      showControls.value = true

      // 视频暂停,显示遮罩
      videoRef.addEventListener("pause", () => {
        showControls.value = false
      })
    }

    // swiper切换,中止视频播放
    function swiperChange() {
      if (dataList.videoList && dataList.videoList.length) {
        for (let index = 0; index < dataList.videoList.length; index++) {
          const element = dataList.videoList[index];
          getVideoBase64(element.url, index)
          const videoRef: any = document.getElementById(`video${index}`)
          videoRef.pause()
        }
      }
    }

    let dataURL = '';
    const getVideoBase64 = (url, videoIndex) => {
      // console.log(url, "1111111111111")
      return new Promise(function (resolve) {
        
        const video = document.createElement('video');

        video.setAttribute('crossOrigin', 'anonymous'); // 处理跨域
        video.setAttribute('src', url);
        video.setAttribute('preload', 'auto');
        video.addEventListener('loadeddata', function () {
          const canvas = document.createElement('canvas');
          const width = video.videoWidth || 115; // canvas的尺寸和图片一样
          const height = video.videoHeight || 114;// 设置默认宽高为  400  240 
          canvas.width = width;
          canvas.height = height;
          canvas.getContext('2d').drawImage(video, 0, 0, width, height); // 绘制canvas
          dataURL = canvas.toDataURL('image/jpeg'); // 转换为base64
          // document.getElementById('video' + videoIndex).setAttribute('poster', dataURL)
          document.getElementById('extra').style.background =`url(${dataURL})`;
          document.getElementById('extra').style.backgroundSize ='cover';
          document.getElementById('extra').style.backgroundPosition ="center center";
          console.log(document.getElementById('extra').style.background, "222222222")
          resolve(dataURL);
        });
      });
    }

    if (dataList.videoList && dataList.videoList.length) {
      getVideoBase64(dataList.videoList[0].url, 0)
    }

    const clickPlayVideo = (videoPath) => {
      console.log(videoPath, "原生播放传递路径")
      if (videoPath) {
        playVideo(videoPath)
      }
    }

    return {
      index,
      showDialog,
      show,
      picUrl,
      onChange,
      trackList,
      openTrack,
      reviewPic,
      startPosition,
      playSwiperVideo,
      showControls,
      dataURL,
      swiperChange,
      getVideoBase64,
      clickPlayVideo,
      playVideo,
    }
  }
})
</script>
<style scoped lang="scss">
.rightInfo {
  display: flex;
  flex-direction: row;
  margin: 19px 0 19px 10px;
  border-radius: 10px;
  padding: 10px 12px;
  justify-content: flex-end;

  .avatar>img {
    width: 38px;
    height: 38px;
    border-radius: 50%;
  }

  .info {
    margin-right: 8px;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;

    .timeBar {
      display: flex;
      flex-direction: row;
      justify-content: flex-end;
      width: 100%;

      .nickname {
        font-weight: bold;
        color: #3C3C3C;
        font-size: $font12;
      }

      .time {
        margin: 0 8px 8px 0;
        color: #999999;
        font-size: $font12;
      }
    }

    .mainInfo {
      max-width: 244px;
      display: flex;
      background: #ffffff;
      border-radius: 10px;
      font-size: $font12;
      padding: 10px 12px;
      width: auto;
      flex-direction: column;

      .infoLine {
        margin: 5px 0;

        .infoName {
          color: #7A7A7A;
        }

        .infoValue {
          color: #3C3C3C;
          font-weight: bold;
          margin-left: 5px;
          text-align: end;
          line-break: anywhere;
          text-align: left;
        }

        .infoLineImg {
          color: #7A7A7A;
          display: flex;
          justify-content: flex-end;

          .extra {
            max-width: 140px;
            height: 105px;
            border-radius: 8px;
            margin-left: 5px;
            border: 1px solid #b7b7b74d;
            position: relative;

            &-swiper {
              width: 100%;
              height: 100%;

              img {
                width: 100%;
                height: 100%;
              }

              video {
                width: 100%;
                height: 100%;
                z-index: -100;
              }

              .play {
                width: 100%;
                height: 100%;
                position: absolute;
                top: 0;
                left: 0;
                display: flex;
                align-items: center;
                justify-content: center;

                .btn {
                  width: 30px;
                  height: 30px;
                }
              }
            }

            &-indicator {
              position: absolute;
              top: 2px;
              right: 2px;
              background-color: #7a7a7a;
              padding: 0 4px;
              height: 20px;
              line-height: 20px;
              color: #ffffff;
              border-radius: 8px;
            }
          }

          .imgNum {
            width: 23px;
            height: 20px;
            background: #7a7a7a;
            border-radius: 8px;
            color: #ffffff;
            position: relative;
            text-align: center;
            top: 5px;
            left: 140px;
            line-height: 20px;
          }
        }

        .infoTitle {
          font-weight: bold;
          font-size: $font14;
          color: #3C3C3C;
        }

        .trace {
          font-size: $font12;
          font-weight: bold;
          color: #e6262c;
          margin-left: 14px;
        }
      }

      .infoLineImg {
        color: #3C3C3C;
        display: flex;
        justify-content: flex-start;

        .extra {
          width: 140px;
          height: 105px;
          border-radius: 8px;
          margin-left: 5px;
          border: 1px solid #b7b7b74d;

          &-swiper {
            width: 100%;
            height: 100%;

            img {
              width: 100%;
              height: 100%;
            }

            video {
              width: 100%;
              height: 100%;
              z-index: -100;
            }

            .play {
              width: 100%;
              height: 100%;
              position: absolute;
              top: 0;
              left: 0;
              display: flex;
              align-items: center;
              justify-content: center;

              .btn {
                width: 30px;
                height: 30px;
              }
            }
          }

          &-indicator {
            position: absolute;
            top: 2px;
            right: 2px;
            background-color: #7a7a7a;
            padding: 0 4px;
            height: 20px;
            line-height: 20px;
            color: #ffffff;
            border-radius: 8px;
          }
        }

        .imgNum {
          width: 23px;
          height: 20px;
          background: #7a7a7a;
          border-radius: 8px;
          color: #ffffff;
          position: relative;
          text-align: center;
          top: 5px;
          right: 30px;
          line-height: 20px;
        }

        .infoName {
          color: #7A7A7A;
        }
      }
    }


  }

  :deep(.van-overlay) {
    .block {
      width: calc(100% - 84px);
      max-height: 487px;
      height: 487px;
      top: 50%;
      position: absolute;
      left: 50%;
      transform: translate(-50%, -50%);
      background: #ffffff;
      border-radius: 6px;

      .content {
        height: 480px;

        .traceTitle {
          font-size: $font18;
          font-weight: bold;
          text-align: center;
          color: #3c3c3c;
          padding: 19px;
        }

        .opacity {
          width: 100%;
          height: 42px;
          background: linear-gradient(180deg, rgba(255, 255, 255, 0.00), #ffffff 87%);
          position: relative;
          bottom: 30px;
        }

        .detail {
          height: 410px !important;
          overflow: auto;
        }

        &-track {
          height: 400px;
          overflow: auto;
        }
      }

      .cancel {
        text-align: center;
        height: 48px;
        line-height: 48px;
        background: #ffffff;
        font-size: $font16;
        font-weight: bold;
        border-top: 1px solid #f0f0f0;
        border-radius: 0 0 6px 6px;
      }
    }
  }
}
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值