Browse Source

热点详情

任一存 2 years ago
parent
commit
1aea01ed9d

BIN
src/assets/images/swkk/audio-pause.png


BIN
src/assets/images/swkk/audio-play.png


BIN
src/assets/images/swkk/hotspot-video-bg.png


+ 207 - 0
src/components/Audio.vue

@@ -0,0 +1,207 @@
+<template>
+  <div class="Audio">
+    <audio
+      ref="audioTag"
+      :class="`noshow`"
+      :src="audioSrc"
+    />
+
+    <div class="audiocon">
+      <div class="time">
+        <span>{{ time }}</span><span> / {{ allTime }}</span>
+      </div>
+
+      <div class="second-line">
+        <!-- 按钮 -->
+        <button class="leftBtn">
+          <img
+            :src="require(`@/assets/images/swkk/${isPlay ? 'audio-pause' : 'audio-play'}.png`)"
+            alt=""
+            @click="switchPlayStatus"
+          >
+        </button>
+
+        <div
+          class="bar"
+          @click="seekTime"
+        >
+          <div
+            class="progress"
+            :style="{
+              width: currentProgress + '%',
+            }"
+          />
+          <div
+            class="dot"
+            :style="{
+              left: currentProgress + '%',
+            }"
+          />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "AudioComp",
+  props: {
+    audioSrc: {
+      type: String,
+    },
+  },
+  data() {
+    return {
+      time: 0,
+      audioNode: "",
+      isPlay: false,
+      currentProgress: 0,
+      allTime: 0,
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.audioNode = this.$refs.audioTag
+      this.audioNode.addEventListener("loadedmetadata", (e) => {
+        this.time = this.transTime(e.currentTarget.duration)
+        this.allTime = this.transTime(e.currentTarget.duration)
+        // this.audioNode.play()
+        // this.isPlay = true
+      })
+
+      // document.addEventListener(
+      //   "WeixinJSBridgeReady",
+      //   function () {
+      //     this.audioNode.play()
+      //   },
+      //   false
+      // )
+
+      this.audioNode.addEventListener("timeupdate", () => {
+        this.updateProgress()
+      })
+
+      this.audioNode.addEventListener("timeupdate", () => {
+        this.updateProgress()
+      })
+
+      this.audioNode.addEventListener("ended", () => {
+        this.audioEnded()
+      })
+    })
+  },
+  methods: {
+    switchPlayStatus() {
+      if (this.audioNode.paused) {
+        this.audioNode.play()
+        this.isPlay = true
+      } else {
+        this.audioNode.pause()
+        this.isPlay = false
+      }
+    },
+    play() {
+      this.audioNode.play()
+      this.isPlay = true
+    },
+    pause() {
+      this.audioNode.pause()
+      this.isPlay = false
+    },
+    transTime(time) {
+      var duration = parseInt(time)
+      var minute = parseInt(duration / 60)
+      var sec = (duration % 60) + ""
+      var isM0 = ":"
+      if (minute == 0) {
+        minute = "00"
+      } else if (minute < 10) {
+        minute = "0" + minute
+      }
+      if (sec.length == 1) {
+        sec = "0" + sec
+      }
+      return minute + isM0 + sec
+    },
+    updateProgress() {
+      this.currentProgress = (this.audioNode.currentTime / this.audioNode.duration) * 100
+      this.time = this.transTime(this.audioNode.currentTime)
+    },
+
+    audioEnded() {
+      this.audioNode.currentTime = 0
+      this.audioNode.pause()
+      this.isPlay = false
+    },
+
+    seekTime(e) {
+      let rate = e.offsetX / e.target.clientWidth
+      this.audioNode.currentTime = this.audioNode.duration * rate
+      this.updateProgress()
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.Audio {
+  position: relative;
+  #audioTag {
+    display: none;
+  }
+  .audiocon {
+    position: absolute;
+    left: 0;
+    width: 100%;
+    top: 45%;
+    transform: translateY(-50%);
+    .time {
+      text-align: center;
+      color: #930909;
+      font-size: 1.67rem;
+    }
+    .second-line {
+      display: flex;
+      align-items: center;
+      .leftBtn {
+        flex: 0 0 auto;
+        width: 5rem;
+        height: 5rem;
+        > img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+      .bar {
+        position: relative;
+        height: 0.83rem;
+        flex: 1 0 1px;
+        margin-left: 2rem;
+        background-color: #CEA763;
+        border-radius: 0.83rem;
+        .progress {
+          position: absolute;
+          top: 0;
+          left: 0;
+          height: 100%;
+          width: 50%;
+          background-color: #930909;
+          border-radius: 0.83rem;
+          pointer-events: none;
+        }
+        .dot {
+          width: 2.92rem;
+          height: 2.92rem;
+          border-radius: 50%;
+          position: absolute;
+          top: 50%;
+          transform: translate(-50%, -50%);
+          border: 0.42rem solid #930909;
+          background-color: #CEA763;
+        }
+      }
+    }
+  }
+}
+</style>

+ 177 - 80
src/components/HotspotDetail.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="hotspot-detail">
-    <button
+    <!-- <button
       class="desc"
       @click="isShowDesc = true"
     >
@@ -9,13 +9,13 @@
         alt="详情"
         draggable="false"
       >
-    </button>
+    </button> -->
 
-    <h1>{{ titleForShow }}</h1>
+    <h1 v-html="titleForShow" />
 
     <button
       class="close"
-      @click="routeBack"
+      @click="$emit('close')"
     >
       <img
         src="@/assets/images/close.png"
@@ -25,28 +25,29 @@
     </button>
 
     <div
-      v-show="typesToShow[currentTabIdx] && typesToShow[currentTabIdx].name === '视频'"
-      class="swiper-wrapper-mine"
+      v-if="typesToShow[currentTabIdx].name === '视频'"
+      class="swiper-wrapper-mine video-wrap"
     >
       <div
-        class="swiper-root"
+        class="swiper-root swiper-root"
       >
         <div
           class="swiper-wrapper"
         >
-          <video
+          <div
             v-for="(item, index) in typesToShow[currentTabIdx].list"
             :key="index"
-            :src="`https://4dkk.4dage.com/scene_edit_data/KJ-aigSkgvRWR/user/${item.url}`"
-            controls
-            controlslist="nodownload"
-            disablePictureInPicture
             class="swiper-slide"
-          />
+          >
+            <video
+              ref="video"
+              :src="`https://4dkk.4dage.com/scene_edit_data/KJ-aigSkgvRWR/user/${item.url}`"
+              controls
+              controlslist="nodownload"
+              disablePictureInPicture
+            />
+          </div>
         </div>
-        <!-- <div class="
-            swiper-pagination"
-          /> -->
         <div class="swiper-pagination">
           <span class="cur">{{ currentSlideIdx + 1 }}</span> / <span>{{ typesToShow[currentTabIdx].list.length }}</span>
         </div>
@@ -56,8 +57,8 @@
     </div>
 
     <div
-      v-show="typesToShow[currentTabIdx] && typesToShow[currentTabIdx].name === '模型'"
-      class="swiper-wrapper-mine"
+      v-if="typesToShow[currentTabIdx].name === '模型'"
+      class="swiper-wrapper-mine model-wrap"
     >
       <div
         class="swiper-root"
@@ -73,7 +74,6 @@
             class="swiper-slide"
           />
         </div>
-        <!-- <div class="swiper-pagination" /> -->
         <div class="swiper-pagination">
           <span class="cur">{{ currentSlideIdx + 1 }}</span> / <span>{{ typesToShow[currentTabIdx].list.length }}</span>
         </div>
@@ -82,9 +82,9 @@
       </div>
     </div>
 
-    <!-- <div
+    <div
       v-show="typesToShow[currentTabIdx] && typesToShow[currentTabIdx].name === '音频'"
-      class="swiper-wrapper-mine"
+      class="swiper-wrapper-mine audio-wrap"
     >
       <div
         class="swiper-root"
@@ -92,11 +92,12 @@
         <div
           class="swiper-wrapper"
         >
-          <audio
+          <Audio
             v-for="(item, index) in typesToShow[currentTabIdx].list"
+            ref="audio-comp"
             :key="index"
-            class="swiper-slide"
-            :src="`https://4dkk.4dage.com/scene_edit_data/KJ-aigSkgvRWR/user/${item.url}`"
+            class="audio-custom swiper-slide"
+            :audio-src="`https://4dkk.4dage.com/scene_edit_data/KJ-aigSkgvRWR/user/${item.url}`"
           />
         </div>
         <div class="swiper-pagination">
@@ -105,11 +106,11 @@
         <div class="swiper-button-prev" />
         <div class="swiper-button-next" />
       </div>
-    </div> -->
+    </div>
 
     <div
       v-show="typesToShow[currentTabIdx] && typesToShow[currentTabIdx].name === '图片'"
-      class="swiper-wrapper-mine"
+      class="swiper-wrapper-mine image-wrap"
     >
       <div
         class="swiper-root"
@@ -141,7 +142,6 @@
             draggable="false"
           >
         </div>
-        <!-- <div class="swiper-pagination" /> -->
         <div class="swiper-pagination">
           <span class="cur">{{ currentSlideIdx + 1 }}</span> / <span>{{ typesToShow[currentTabIdx].list.length }}</span>
         </div>
@@ -174,11 +174,28 @@
 <script>
 import Swiper from 'swiper/swiper-bundle.esm.js'
 import 'swiper/swiper-bundle.css'
+import Audio from "@/components/Audio.vue"
 
 export default {
+  components: {
+    Audio,
+  },
+  props: {
+    hotspotList: {
+      type: Array,
+      required: true,
+    }
+  },
   data() {
     return {
-      types: [
+      currentTabIdx: 0,
+      currentSlideIdx: 0,
+      isShowDesc: false,
+    }
+  },
+  computed: {
+    types() {
+      const ret = [
         {
           key: 'video',
           name: '视频',
@@ -241,13 +258,20 @@ export default {
             // },
           ]
         },
-      ],
-      currentTabIdx: 0,
-      currentSlideIdx: 0,
-      isShowDesc: false,
-    }
-  },
-  computed: {
+      ]
+      for (const hotspot of this.hotspotList) {
+        const targetTypeItem = ret.find((item) => {
+          return item.key === hotspot.type
+        })
+        for (const mediaItem of hotspot.media[hotspot.type]) {
+          targetTypeItem.list.push({
+            title: mediaItem.name || hotspot.content,
+            url: mediaItem.src,
+          })
+        }
+      }
+      return ret
+    },
     titleForShow() {
       try {
         return this.typesToShow[this.currentTabIdx].list[this.currentSlideIdx].title
@@ -259,50 +283,76 @@ export default {
       return this.types.filter((item) => {
         return item.list.length
       })
-    }
+    },
   },
-  mounted() {
-    console.log('HotspotDetail mount!')
-    console.log(this.$route.params.hotspotList)
-    for (const hotspot of this.$route.params.hotspotList) {
-      const targetTypeItem = this.types.find((item) => {
-        return item.key === hotspot.type
-      })
-      for (const mediaItem of hotspot.media[hotspot.type]) {
-        targetTypeItem.list.push({
-          title: mediaItem.name || hotspot.content,
-          url: mediaItem.src,
-        })
-      }
-    }
-    console.log(this.types)
-
-    this.$nextTick(() => {
-      const that = this
-      const swiper = new Swiper('.swiper-root', {
-      // If we need pagination
-        // pagination: {
-        //   el: '.swiper-pagination',
-        // },
+  watch: {
+    currentTabIdx: {
+      handler(vNew) {
+        this.currentSlideIdx = 0
+        this.$nextTick(() => {
+          const that = this
+          const swiper = new Swiper('.swiper-root', {
+            // If we need pagination
+            // pagination: {
+            //   el: '.swiper-pagination',
+            // },
 
-        // Navigation arrows
-        navigation: {
-          nextEl: '.swiper-button-next',
-          prevEl: '.swiper-button-prev',
-        },
+            // Navigation arrows
+            navigation: {
+              nextEl: '.swiper-button-next',
+              prevEl: '.swiper-button-prev',
+            },
 
-        on: {
-          slideChange: function(e) {
-            that.currentSlideIdx = e.activeIndex
-          }
-        }
-      })
-    })
+            on: {
+              afterInit: function (e) {
+                if (that.types[vNew].key === 'video') {
+                  that.$refs.video[0].play()
+                }
+                if (that.types[vNew].key === 'audio') {
+                  that.$refs['audio-comp'][0].play()
+                }
+              },
+              slideChange: function(e) {
+                that.currentSlideIdx = e.activeIndex
+                if (that.types[vNew].key === 'video') {
+                  for (let index = 0; index < that.$refs.video.length; index++) {
+                    if (index !== that.currentSlideIdx) {
+                      that.$refs.video[index].pause()
+                    } else {
+                      that.$refs.video[index].play()
+                    }
+                  }
+                }
+                if (that.types[vNew].key === 'audio') {
+                  for (let index = 0; index < that.$refs['audio-comp'].length; index++) {
+                    if (index !== that.currentSlideIdx) {
+                      that.$refs['audio-comp'][index].pause()
+                    } else {
+                      that.$refs['audio-comp'][index].play()
+                    }
+                  }
+                }
+              }
+            }
+          })
+        })
+      },
+      immediate: true,
+    },
+  },
+  mounted() {
+    this.$msgCenter.publish('swkk-guide-bar-show')
+    this.mustMute()
+  },
+  beforeDestroy() {
+    this.$msgCenter.publish('swkk-guide-bar-hide')
+    this.cancelMustMute()
   },
   methods: {
-    routeBack: globalUtils.throttle(function() {
-      this.$router.go(-1)
-    }, 500)
+    ...globalMapMutations([
+      'mustMute',
+      'cancelMustMute',
+    ])
   }
 }
 </script>
@@ -330,7 +380,7 @@ export default {
   }
   > h1 {
     position: absolute;
-    top: 4rem;
+    top: 5rem;
     left: 10.46rem;
     right: 10.46rem;
     text-align: center;
@@ -364,10 +414,6 @@ export default {
       overflow: hidden;
       height: 100%;
       .swiper-wrapper {
-        // 用类选择器不会生效
-        img {
-          object-fit: contain;
-        }
       }
       // .swiper-pagination {
       //   top: 100%;
@@ -387,7 +433,7 @@ export default {
       // }
       .swiper-pagination {
         position: absolute;
-        top: 100%;
+        top: calc(100% + 1em);
         left: 50%;
         transform: translateX(-50%);
         font-size: 1.33rem;
@@ -421,6 +467,57 @@ export default {
     }
   }
 
+  .swiper-wrapper-mine.video-wrap {
+    height: calc(31.5rem * 0.85);
+    width: calc(43.5rem * 0.85);
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -70%);
+    .swiper-root {
+      .swiper-wrapper {
+        .swiper-slide {
+          background-image: url(@/assets/images/swkk/hotspot-video-bg.png);
+          background-size: contain;
+          background-repeat: no-repeat;
+          padding: 5.67rem 2.21rem 1.88rem 1.8rem;
+          > video {
+            width: 100%;
+            height: 100%;
+          }
+        }
+      }
+    }
+  }
+  .swiper-wrapper-mine.model-wrap {
+    .swiper-root {
+      .swiper-wrapper {
+      }
+    }
+  }
+  .swiper-wrapper-mine.audio-wrap {
+    width: calc(100% - 1.67rem * 2 - 1.83rem * 2 - 1.67rem * 2);
+    height: 30rem;
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -70%);
+    .swiper-root {
+      width: 100%;
+      .swiper-wrapper {
+      }
+    }
+  }
+  .swiper-wrapper-mine.image-wrap {
+    .swiper-root {
+      .swiper-wrapper {
+        > img {
+          object-fit: contain;
+        }
+      }
+    }
+  }
+
   > .type-tabbar {
     position: absolute;
     bottom: 11.9%;

+ 0 - 13
src/router/index.js

@@ -8,7 +8,6 @@ import SwkkView from "@/views/SwkkView.vue"
 import ObliqueView from "@/views/ObliqueView.vue"
 import PanoView from "@/views/PanoView.vue"
 import PanoList from "@/components/PanoList.vue"
-import HotspotDetail from "@/components/HotspotDetail.vue"
 import TestView from "@/components/TestView.vue"
 
 Vue.use(VueRouter)
@@ -53,23 +52,11 @@ const routes = [
       isShowBottomBar: true,
       canFullScreen: true,
     },
-    children: [
-      {
-        path: 'hotspot-detail',
-        name: 'HotspotDetail',
-        component: HotspotDetail,
-        meta: {
-          isShowBottomBar: false,
-          canFullScreen: false,
-        }
-      },
-    ],
     beforeEnter (to, from, next) {
       if (from.name === 'HomeView') {
         // 从首页过来的,需要reload。此时location还没有变。
         let shabi = to.fullPath
         location.hash = shabi
-        alert('reload!!!')
         location.reload()
       } else {
         // 无论是从首页还是从不同楼层过来,导致reload。

+ 23 - 11
src/views/SwkkView.vue

@@ -165,12 +165,21 @@
       </ul>
     </div>
 
-    <router-view />
+    <HotspotDetail
+      v-if="isShowDetail"
+      class="hotspot-detail"
+      :hotspot-list="relatedHotspotList"
+      @close="isShowDetail = false"
+    />
   </div>
 </template>
 
 <script>
+import HotspotDetail from "@/components/HotspotDetail.vue"
 export default {
+  components: {
+    HotspotDetail,
+  },
   data() {
     //这里存放数据
     return {
@@ -192,6 +201,7 @@ export default {
       mode: 2,
 
       baseHotData: null,
+      isShowDetail: false,
     }
   },
   computed: {
@@ -355,27 +365,22 @@ export default {
           type: "image"
         }
 
-        let relatedHotspotList = []
+        this.relatedHotspotList = []
         if (e.data.title.split("&")[1]) { // 如果是多个热点合并
           this.baseHotData.forEach((item) => {
             if (item.title.split("&")[1] === e.data.title.split("&")[1]) {
-              relatedHotspotList.push(item)
+              this.relatedHotspotList.push(item)
             }
           })
-          console.log(relatedHotspotList)
+          console.log(this.relatedHotspotList)
         } else { // 单个热点
-          relatedHotspotList.push(e.data)
+          this.relatedHotspotList.push(e.data)
         }
 
         // 聚焦当前点击的热点
         TagView.focus(e.data.sid)
 
-        this.$router.push({
-          name: 'HotspotDetail',
-          params: {
-            hotspotList: relatedHotspotList,
-          },
-        })
+        this.isShowDetail = true
       })
     })
 
@@ -646,5 +651,12 @@ export default {
       }
     }
   }
+  .hotspot-detail {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+  }
 }
 </style>