任一存 пре 3 година
родитељ
комит
f8943b9315
9 измењених фајлова са 351 додато и 0 уклоњено
  1. 1 0
      package.json
  2. 7 0
      src/App.vue
  3. 1 0
      src/components/BottomBar.vue
  4. 236 0
      src/components/UserGuide.vue
  5. 1 0
      src/components/panoDesc.vue
  6. 4 0
      src/config.js
  7. 32 0
      src/views/PanoView.vue
  8. 57 0
      src/views/SwkkView.vue
  9. 12 0
      yarn.lock

+ 1 - 0
package.json

@@ -10,6 +10,7 @@
     "lint": "vue-cli-service lint"
     "lint": "vue-cli-service lint"
   },
   },
   "dependencies": {
   "dependencies": {
+    "@floating-ui/dom": "^1.0.7",
     "axios": "^1.1.3",
     "axios": "^1.1.3",
     "core-js": "^3.8.3",
     "core-js": "^3.8.3",
     "mars3d": "3.4.1",
     "mars3d": "3.4.1",

+ 7 - 0
src/App.vue

@@ -2,6 +2,11 @@
   <div id="app">
   <div id="app">
     <router-view />
     <router-view />
     <BottomBar />
     <BottomBar />
+    <UserGuide
+      :style="{
+        zIndex: $globalConfig.zIndex.userGuide.self,
+      }"
+    />
     <LoadingTip
     <LoadingTip
       v-show="isShowLoading"
       v-show="isShowLoading"
     />
     />
@@ -12,11 +17,13 @@
 import { mapState } from 'vuex'
 import { mapState } from 'vuex'
 import BottomBar from './components/BottomBar.vue'
 import BottomBar from './components/BottomBar.vue'
 import LoadingTip from "@/components/LoadingTip.vue"
 import LoadingTip from "@/components/LoadingTip.vue"
+import UserGuide from "@/components/UserGuide.vue"
 
 
 export default {
 export default {
   components: {
   components: {
     BottomBar,
     BottomBar,
     LoadingTip,
     LoadingTip,
+    UserGuide,
   },
   },
   data() {
   data() {
     return {
     return {

+ 1 - 0
src/components/BottomBar.vue

@@ -1,6 +1,7 @@
 <template>
 <template>
   <div
   <div
     v-if="$route.meta.isShowBottomBar && !ifMustHide"
     v-if="$route.meta.isShowBottomBar && !ifMustHide"
+    id="bottom-bar"
     class="bottom-bar"
     class="bottom-bar"
     :style="{
     :style="{
       zIndex: $globalConfig.zIndex.bottomBar.self,
       zIndex: $globalConfig.zIndex.bottomBar.self,

+ 236 - 0
src/components/UserGuide.vue

@@ -0,0 +1,236 @@
+<template>
+  <div
+    v-if="isShow"
+    class="user-guide"
+  >
+    <div
+      ref="target-mark"
+      class="target-mark"
+      :style="{
+        top: markTop,
+        left: markLeft,
+        width: markWidth,
+        height: markHeight,
+        borderRadius: padding + 'px',
+      }"
+    />
+
+    <div
+      v-if="guideInfo && guideInfo[currentStep]"
+      ref="dialog"
+      class="dialog"
+    >
+      <div
+        ref="arrow"
+        class="arrow"
+      />
+      <h2>{{ guideInfo[currentStep].title }}</h2>
+      <div
+        class="content"
+        v-html="guideInfo[currentStep].content"
+      />
+      <div class="page">
+        {{ currentStep + 1 }}/{{ guideInfo.length }}
+      </div>
+      <button
+        v-show="currentStep > 0"
+        class="prev"
+        @click="currentStep--"
+      >
+        &lt; 上一条
+      </button>
+      <button
+        class="skip"
+        @click="isShow = false"
+      >
+        {{ currentStep === guideInfo.length - 1 ? '完成' : '跳过' }}
+      </button>
+      <button
+        v-show="currentStep < guideInfo.length - 1"
+        class="next"
+        @click="currentStep++"
+      >
+        下一条 &gt;
+      </button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { computePosition, offset, flip, shift, arrow } from '@floating-ui/dom'
+
+export default {
+  props: {
+  },
+  data() {
+    return {
+      padding: 5,
+
+      isShow: false,
+
+      guideInfo: [],
+      currentStep: -1,
+
+      markTop: '',
+      markLeft: '',
+      markWidth: '',
+      markHeight: '',
+    }
+  },
+  watch: {
+    currentStep: {
+      handler(v) {
+        if (v !== -1) {
+          this.getCurrentGuideInfo()
+        }
+      }
+    }
+  },
+  created() {
+    this.$root.userGuide = this
+  },
+  mounted() {
+  },
+  methods: {
+    beginGuide(guideInfo) {
+      // guideInfo = [
+      //   {
+      //     selector: ...,
+      //     title: ...,
+      //     content: ...,
+      //   },
+      // ]
+      this.isShow = true
+      this.guideInfo = guideInfo
+      this.currentStep = 0
+    },
+    getCurrentGuideInfo() {
+      // 设置高亮区域的位置
+      const selector = this.guideInfo[this.currentStep].selector
+      const targetElem = document.querySelector(selector)
+      const rect = targetElem.getBoundingClientRect()
+      this.markTop = rect.y - this.padding + 'px'
+      this.markLeft = rect.x - this.padding + 'px'
+      if (this.guideInfo[this.currentStep].customWidth) {
+        this.markWidth = `calc(${this.guideInfo[this.currentStep].customWidth} + ${this.padding}px * 2)`
+      } else {
+        this.markWidth = `calc(${rect.width}px + ${this.padding}px * 2)`
+      }
+      if (this.guideInfo[this.currentStep].customHeight) {
+        this.markHeight = `calc(${this.guideInfo[this.currentStep].customHeight} + ${this.padding}px * 2)`
+      } else {
+        this.markHeight = `calc(${rect.height}px + ${this.padding}px * 2)`
+      }
+
+      this.$nextTick(() => {
+        // 设置对话框的位置
+        computePosition(this.$refs['target-mark'], this.$refs.dialog, {
+          placement: 'bottom',
+          middleware: [
+            offset(2 * this.$oneRemToPx),
+            flip(),
+            shift({ padding: 12 }),
+            arrow({
+              element: this.$refs.arrow,
+              padding: 3,
+            }),
+          ],
+        }).then(({ x, y, placement, middlewareData }) => {
+          Object.assign(this.$refs.dialog.style, {
+            left: `${x}px`,
+            top: `${y}px`,
+          })
+
+          const { x: arrowX, y: arrowY } = middlewareData.arrow
+          const arrowPlacement = {
+            top: 'bottom',
+            right: 'left',
+            bottom: 'top',
+            left: 'right',
+          }[placement.split('-')[0]]
+          const dialogPlacement2arrowRotate = {
+            top: '-135deg',
+            right: '-45deg',
+            bottom: '45deg',
+            left: '135deg',
+          }
+          Object.assign(this.$refs.arrow.style, {
+            top: 'initial',
+            bottom: 'initial',
+            left: 'initial',
+            right: 'initial',
+          })
+          Object.assign(this.$refs.arrow.style, {
+            left: arrowX != null ? `${arrowX}px` : '',
+            [arrowPlacement]: -this.$oneRemToPx + 'px',
+            transform: `scaleX(0.7) rotate(${dialogPlacement2arrowRotate[placement]})`,
+          })
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.user-guide {
+  position: fixed;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  > .target-mark {
+    position: absolute;
+    box-shadow: 0px 0px 0px 5000px rgba(34, 34, 34, 0.80);
+  }
+  > .dialog {
+    position: absolute;
+    border: 0.08rem solid #D8B275;
+    border-radius: 0.5rem;
+    background-color: rgba(34, 34, 34, 1);
+    padding: 1.54rem;
+    > .arrow {
+      position: absolute;
+      background-color: inherit;
+      width: 2rem;
+      height: 2rem;
+      border: 0.08rem solid transparent;
+      border-left: inherit;
+      border-top: inherit;
+    }
+    > h2 {
+      font-size: 2rem;
+      font-weight: bold;
+      color: #D8B275;
+      line-height: 2.34rem;
+      margin-bottom: 0.42rem;
+    }
+    > .content {
+      font-size: 1.5rem;
+      color: #FFFFFF;
+      line-height: 1.76rem;
+      margin-bottom: 2.42rem;
+    }
+    > button {
+      width: 8.33rem;
+      height: 4.17rem;
+      border-radius: 0.21rem 0.21rem 0.21rem 0.21rem;
+      border: 0.08rem solid #D8B275;
+      min-width: 8.33rem;
+      font-size: 1.5rem;
+      color: #FFFFFF;
+      margin-right: 0.83rem;
+      &:last-of-type {
+        margin-right: initial;
+      }
+    }
+    > .page {
+      position: absolute;
+      top: 2rem;
+      right: 1.54rem;
+      font-size: 1.5rem;
+      color: #FFFFFF;
+    }
+  }
+}
+</style>

+ 1 - 0
src/components/panoDesc.vue

@@ -22,6 +22,7 @@
       </button>
       </button>
       <h1>{{ desc.name }}</h1>
       <h1>{{ desc.name }}</h1>
       <button
       <button
+        id="expand-pano-info"
         class="expand-status"
         class="expand-status"
         :class="{
         :class="{
           shrinked: !isPanoDescExpanded,
           shrinked: !isPanoDescExpanded,

+ 4 - 0
src/config.js

@@ -37,6 +37,10 @@ export default {
         }
         }
       },
       },
     },
     },
+    userGuide: {
+      self: '90',
+      children: {},
+    },
     loading: {
     loading: {
       self: '96',
       self: '96',
       children: {},
       children: {},

+ 32 - 0
src/views/PanoView.vue

@@ -6,6 +6,7 @@
     />
     />
 
 
     <button
     <button
+      id="back-btn"
       class="top back"
       class="top back"
       @click="onClickBack"
       @click="onClickBack"
     >
     >
@@ -18,6 +19,7 @@
     </button>
     </button>
 
 
     <button
     <button
+      id="switch-pano-btn"
       class="top switch-pano"
       class="top switch-pano"
       @click="onClickSwitchPano"
       @click="onClickSwitchPano"
     >
     >
@@ -83,6 +85,36 @@ export default {
   },
   },
   async mounted() {
   async mounted() {
     console.log('this.$route.params.scene: ', this.$route.params.scene)
     console.log('this.$route.params.scene: ', this.$route.params.scene)
+    setTimeout(() => {
+      const haveShownSwkkGuide = localStorage.getItem('haveShownPanoGuide')
+      if (!haveShownSwkkGuide) {
+        localStorage.setItem('haveShownPanoGuide', '1')
+        this.$root.userGuide.beginGuide([
+          {
+            selector: '#back-btn',
+            title: '返回',
+            content: '返回倾斜摄影模型',
+          },
+          ...(this.currentSceneDesc) ? [
+            {
+              selector: '#expand-pano-info',
+              title: '场景信息',
+              content: '查看更多场景信息',
+            },
+          ] : [],
+          {
+            selector: '#switch-pano-btn',
+            title: '全景切换',
+            content: '查看所有航拍全景/地拍全景',
+          },
+          {
+            selector: '#bottom-bar',
+            title: '更多',
+            content: '可回到首页,关闭/开启声音,点赞和分享等',
+          },
+        ])
+      }
+    }, 500)
     this.scene = this.$route.params.scene
     this.scene = this.$route.params.scene
 
 
     window.__krfn = __krfn
     window.__krfn = __krfn

+ 57 - 0
src/views/SwkkView.vue

@@ -8,6 +8,7 @@
 
 
     <menu>
     <menu>
       <button
       <button
+        id="auto-moving"
         :class="{active: isAutoMoving}"
         :class="{active: isAutoMoving}"
         @click="onClickAutoMoving"
         @click="onClickAutoMoving"
       >
       >
@@ -27,6 +28,7 @@
         <div>自动漫游</div>
         <div>自动漫游</div>
       </button>
       </button>
       <button
       <button
+        id="tour-guide"
         :class="{active: isShowTourGuide}"
         :class="{active: isShowTourGuide}"
         @click="onClickCjdl"
         @click="onClickCjdl"
       >
       >
@@ -45,6 +47,7 @@
         <div>场景导览</div>
         <div>场景导览</div>
       </button>
       </button>
       <button
       <button
+        id="qjmy"
         :class="{active: mode === 2}"
         :class="{active: mode === 2}"
         @click="onClickQjmy"
         @click="onClickQjmy"
       >
       >
@@ -63,6 +66,7 @@
         <div>全景漫游</div>
         <div>全景漫游</div>
       </button>
       </button>
       <button
       <button
+        id="mini-model"
         :class="{active: mode === 3}"
         :class="{active: mode === 3}"
         @click="onClickMnmx"
         @click="onClickMnmx"
       >
       >
@@ -81,6 +85,7 @@
         <div>迷你模型</div>
         <div>迷你模型</div>
       </button>
       </button>
       <button
       <button
+        id="overlook"
         :class="{active: mode === 4}"
         :class="{active: mode === 4}"
         @click="onClickDbfs"
         @click="onClickDbfs"
       >
       >
@@ -99,6 +104,7 @@
         <div>顶部俯视</div>
         <div>顶部俯视</div>
       </button>
       </button>
       <button
       <button
+        id="hotspot-list"
         :class="{active: isShowHotspotList}"
         :class="{active: isShowHotspotList}"
         @click="isShowHotspotList = true"
         @click="isShowHotspotList = true"
       >
       >
@@ -121,6 +127,7 @@
     <!-- 右上地图 -->
     <!-- 右上地图 -->
     <div
     <div
       v-show="!isLoading && mode === 2"
       v-show="!isLoading && mode === 2"
+      id="mini-map"
       class="mini-map"
       class="mini-map"
     >
     >
       <div
       <div
@@ -292,6 +299,56 @@ export default {
     }
     }
   },
   },
   mounted() {
   mounted() {
+    setTimeout(() => {
+      const haveShownSwkkGuide = localStorage.getItem('haveShownSwkkGuide')
+      if (!haveShownSwkkGuide) {
+        localStorage.setItem('haveShownSwkkGuide', '1')
+        this.$root.userGuide.beginGuide([
+          {
+            selector: '#auto-moving',
+            title: '自动漫游',
+            content: '自动游览线上场馆',
+          },
+          {
+            selector: '#tour-guide',
+            title: '场景导览',
+            content: '查看场景内所有镜头点位',
+          },
+          {
+            selector: '#qjmy',
+            title: '全景漫游',
+            content: '手动自主漫游',
+          },
+          {
+            selector: '#mini-model',
+            title: '迷你模型',
+            content: '查看场景3D模型',
+          },
+          {
+            selector: '#overlook',
+            title: '顶部俯视',
+            content: '查看场景平面图',
+          },
+          {
+            selector: '#hotspot-list',
+            title: '热点列表',
+            content: '查看场景内所有交互热点',
+          },
+          {
+            selector: '#bottom-bar',
+            title: '更多',
+            content: '可回到首页,关闭/开启声音,点赞和分享等',
+          },
+          {
+            selector: '#mini-map',
+            title: '地图',
+            content: '可切换楼层,或查看场景3D模型',
+            customWidth: '18rem',
+            customHeight: '18rem + 4.6rem',
+          },
+        ])
+      }
+    }, 500)
     this.$msgCenter.publish('show-loading')
     this.$msgCenter.publish('show-loading')
     let floor = this.$route.query.floor
     let floor = this.$route.query.floor
     this.floor = floor
     this.floor = floor

+ 12 - 0
yarn.lock

@@ -980,6 +980,18 @@
     minimatch "^3.0.4"
     minimatch "^3.0.4"
     strip-json-comments "^3.1.1"
     strip-json-comments "^3.1.1"
 
 
+"@floating-ui/core@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.0.2.tgz#d06a66d3ad8214186eda2432ac8b8d81868a571f"
+  integrity sha512-Skfy0YS3NJ5nV9us0uuPN0HDk1Q4edljaOhRBJGDWs9EBa7ZVMYBHRFlhLvvmwEoaIM9BlH6QJFn9/uZg0bACg==
+
+"@floating-ui/dom@^1.0.7":
+  version "1.0.7"
+  resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.0.7.tgz#9e8e6615ce03e5ebc6a4ae879640a199a366f86d"
+  integrity sha512-6RsqvCYe0AYWtsGvuWqCm7mZytnXAZCjWtsWu1Kg8dI3INvj/DbKlDsZO+mKSaQdPT12uxIW9W2dAWJkPx4Y5g==
+  dependencies:
+    "@floating-ui/core" "^1.0.2"
+
 "@hapi/hoek@^9.0.0":
 "@hapi/hoek@^9.0.0":
   version "9.3.0"
   version "9.3.0"
   resolved "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
   resolved "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"