Browse Source

style: --

chenlei 1 year ago
parent
commit
639b625cb1
46 changed files with 610 additions and 266 deletions
  1. 1 0
      package.json
  2. BIN
      public/relic-data/big-photo/第107页-481.png
  3. BIN
      public/relic-data/big-photo/第112页-535.png
  4. BIN
      public/relic-data/big-photo/第116页-558.PNG
  5. BIN
      public/relic-data/big-photo/第139页-651.png
  6. BIN
      public/relic-data/big-photo/第140页-658.png
  7. 3 3
      public/relic-data/data.json
  8. 30 0
      src/App.vue
  9. BIN
      src/assets/images/game-entry-boat-highlight.png
  10. BIN
      src/assets/images/game-entry-boat.png
  11. BIN
      src/assets/images/game-entry-jigsaw-highlight.png
  12. BIN
      src/assets/images/game-entry-jigsaw.png
  13. BIN
      src/assets/images/game-entry-page-bg.jpg
  14. BIN
      src/assets/images/game-entry-page-title.png
  15. BIN
      src/assets/images/game-entry-relic-show-highlight.png
  16. BIN
      src/assets/images/game-entry-relic-show.png
  17. BIN
      src/assets/images/hotspot-relic/tipsbox-min.png
  18. BIN
      src/assets/images/play.png
  19. BIN
      src/assets/images/pose3-min.png
  20. BIN
      src/assets/images/ship-game/Group 493-min.png
  21. BIN
      src/assets/images/ship-game/Group485-min.png
  22. BIN
      src/assets/videos.rar
  23. 19 16
      src/components/CameraContent-1-1-1.vue
  24. 14 15
      src/components/CameraContent-1-2-1.vue
  25. 8 15
      src/components/CameraContent-1-2-2.vue
  26. 4 2
      src/components/CameraContent-1-2-3.vue
  27. 2 1
      src/components/CameraContent-1-3-1.vue
  28. 1 0
      src/components/CameraContent-2-1-1.vue
  29. 1 3
      src/components/CameraContent-2-1-3.vue
  30. 0 2
      src/components/CameraContent-3-1-1.vue
  31. 2 1
      src/components/CameraContent-3-1-3.vue
  32. 3 8
      src/components/CameraContent-3-2-3.vue
  33. 15 29
      src/components/CharacterDesc.vue
  34. 31 13
      src/components/GameEntryPage.vue
  35. 37 21
      src/components/HotspotDialog-1.vue
  36. 50 10
      src/components/MsgContent.vue
  37. 7 3
      src/components/StartUp.vue
  38. 129 21
      src/components/UserGuide.vue
  39. 1 0
      src/store/index.js
  40. 8 6
      src/useFunctions/useSmoothSwipe.js
  41. 4 2
      src/views/EpilogueView.vue
  42. 80 24
      src/views/HomeView.vue
  43. 31 28
      src/views/PanoView.vue
  44. 40 32
      src/views/RelicList.vue
  45. 57 11
      src/views/ShipGame/ShipGameView.vue
  46. 32 0
      yarn.lock

+ 1 - 0
package.json

@@ -20,6 +20,7 @@
     "qrcode": "^1.5.3",
     "swiper": "^10.0.4",
     "v-viewer": "^3.0.11",
+    "vconsole": "^3.15.1",
     "viewerjs": "^1.11.6",
     "vue": "^3.2.13",
     "vue-router": "^4.0.3",

BIN
public/relic-data/big-photo/第107页-481.png


BIN
public/relic-data/big-photo/第112页-535.png


BIN
public/relic-data/big-photo/第116页-558.PNG


BIN
public/relic-data/big-photo/第139页-651.png


BIN
public/relic-data/big-photo/第140页-658.png


File diff suppressed because it is too large
+ 3 - 3
public/relic-data/data.json


+ 30 - 0
src/App.vue

@@ -419,6 +419,36 @@ button.logo{
   font-size: 14px;
   font-family: "Source Han Sans SC light";
 }
+
+@media screen and (max-height: 480px) {
+  [class^="camera-content-"] {
+    button.return {
+      margin-left: constant(safe-area-inset-left);
+      margin-left: env(safe-area-inset-left);
+      width: 4vw !important;
+      height: 4vw !important;
+      z-index: 10;
+    }
+  }
+}
+
+@keyframes hotspot-icon-animation {
+  0% {
+    transform: translate(0, 0);
+  }
+  100% {
+    transform: translate(0, -100%);
+  }
+}
+
+@keyframes character-default-animation {
+  0% {
+    transform: translate(0, 0);
+  }
+  100% {
+    transform: translate(-100%, 0);
+  }
+}
 </style>
 
 <style lang="less" scoped>

BIN
src/assets/images/game-entry-boat-highlight.png


BIN
src/assets/images/game-entry-boat.png


BIN
src/assets/images/game-entry-jigsaw-highlight.png


BIN
src/assets/images/game-entry-jigsaw.png


BIN
src/assets/images/game-entry-page-bg.jpg


BIN
src/assets/images/game-entry-page-title.png


BIN
src/assets/images/game-entry-relic-show-highlight.png


BIN
src/assets/images/game-entry-relic-show.png


BIN
src/assets/images/hotspot-relic/tipsbox-min.png


BIN
src/assets/images/play.png


BIN
src/assets/images/pose3-min.png


BIN
src/assets/images/ship-game/Group 493-min.png


BIN
src/assets/images/ship-game/Group485-min.png


BIN
src/assets/videos.rar


+ 19 - 16
src/components/CameraContent-1-1-1.vue

@@ -14,7 +14,10 @@
           :class="{
             active: currentSwitchIdx === 0
           }"
-          @click.stop="currentSwitchIdx = 0"
+          @click.stop="() => {
+            currentSwitchIdx = 0
+            checkedHotspotIdx = -1
+          }"
         >
           设计
         </button>
@@ -108,8 +111,9 @@
         <button
           class="hotspot"
           :class="{
-            active: displayingHotspotIdx === 0
+            active: hotspotIdx === 0
           }"
+          @click="checkedHotspotIdx = 0"
           @mouseenter="displayingHotspotIdx = 0"
           @mouseleave="displayingHotspotIdx = -1"
         >
@@ -126,8 +130,9 @@
         <button
           class="hotspot"
           :class="{
-            active: displayingHotspotIdx === 1
+            active: hotspotIdx === 1
           }"
+          @click="checkedHotspotIdx = 1"
           @mouseenter="displayingHotspotIdx = 1"
           @mouseleave="displayingHotspotIdx = -1"
         >
@@ -144,8 +149,9 @@
         <button
           class="hotspot"
           :class="{
-            active: displayingHotspotIdx === 2
+            active: hotspotIdx === 2
           }"
+          @click="checkedHotspotIdx = 2"
           @mouseenter="displayingHotspotIdx = 2"
           @mouseleave="displayingHotspotIdx = -1"
         >
@@ -163,8 +169,9 @@
         <button
           class="hotspot"
           :class="{
-            active: displayingHotspotIdx === 3
+            active: hotspotIdx === 3
           }"
+          @click="checkedHotspotIdx = 3"
           @mouseenter="displayingHotspotIdx = 3"
           @mouseleave="displayingHotspotIdx = -1"
         >
@@ -181,12 +188,12 @@
         <div
           class="desc"
         >
-          <h3 v-if="layoutDataList[displayingHotspotIdx+1].title">
-            {{ layoutDataList[displayingHotspotIdx+1].title }}
+          <h3 v-if="layoutDataList[hotspotIdx+1].title">
+            {{ layoutDataList[hotspotIdx+1].title }}
           </h3>
-          <div class="hotspot-detail text-indent">
+          <div :key="hotspotIdx" class="hotspot-detail text-indent">
             <p
-              v-for="(item, idx) in layoutDataList[displayingHotspotIdx+1].detail.split('\n')"
+              v-for="(item, idx) in layoutDataList[hotspotIdx+1].detail.split('\n')"
               :key="idx"
             >
               {{ item }}
@@ -199,18 +206,12 @@
 </template>
 
 <script setup>
-import { ref, computed, watch, onMounted } from "vue"
-import { useRoute, useRouter } from "vue-router"
-import { useStore } from "vuex"
+import { ref, computed } from "vue"
 const {
   windowSizeInCssForRef,
   windowSizeWhenDesignForRef,
 } = useSizeAdapt(1920, 968)
 
-const route = useRoute()
-const router = useRouter()
-const store = useStore()
-
 const emit = defineEmits(['close'])
 
 const currentSwitchIdx = ref(0)
@@ -249,6 +250,8 @@ const layoutDataList = [
 ]
 
 const displayingHotspotIdx = ref(-1)
+const checkedHotspotIdx = ref(-1)
+const hotspotIdx = computed(() => displayingHotspotIdx.value > - 1 ? displayingHotspotIdx.value : checkedHotspotIdx.value)
 
 const isCharacterSpecialMoving1 = ref(0)
 const isCharacterSpecialMoving2 = ref(0)

+ 14 - 15
src/components/CameraContent-1-2-1.vue

@@ -13,13 +13,13 @@
         class="map-wrap"
       >
         <div
-          v-if="displayingHotspotIdx !== -1"
+          v-if="hotspotIdx !== -1"
           class="desc"
         >
-          <h3>{{ layoutDataList[displayingHotspotIdx].title }}</h3>
+          <h3>{{ layoutDataList[hotspotIdx].title }}</h3>
           <div class="hotspot-detail">
             <p
-              v-for="(item, idx) in layoutDataList[displayingHotspotIdx].detail.split('\n')"
+              v-for="(item, idx) in layoutDataList[hotspotIdx].detail.split('\n')"
               :key="idx"
               class="text-indent"
             >
@@ -30,8 +30,9 @@
         <button
           class="hotspot"
           :class="{
-            active: displayingHotspotIdx === 0
+            active: hotspotIdx === 0
           }"
+          @click="checkedHotspotIdx = 0"
           @mouseenter="displayingHotspotIdx = 0"
           @mouseleave="displayingHotspotIdx = -1"
         >
@@ -48,8 +49,9 @@
         <button
           class="hotspot"
           :class="{
-            active: displayingHotspotIdx === 1
+            active: hotspotIdx === 1
           }"
+          @click="checkedHotspotIdx = 1"
           @mouseenter="displayingHotspotIdx = 1"
           @mouseleave="displayingHotspotIdx = -1"
         >
@@ -66,8 +68,9 @@
         <button
           class="hotspot"
           :class="{
-            active: displayingHotspotIdx === 2
+            active: hotspotIdx === 2
           }"
+          @click="checkedHotspotIdx = 2"
           @mouseenter="displayingHotspotIdx = 2"
           @mouseleave="displayingHotspotIdx = -1"
         >
@@ -84,8 +87,9 @@
         <button
           class="hotspot"
           :class="{
-            active: displayingHotspotIdx === 3
+            active: hotspotIdx === 3
           }"
+          @click="checkedHotspotIdx = 3"
           @mouseenter="displayingHotspotIdx = 3"
           @mouseleave="displayingHotspotIdx = -1"
         >
@@ -105,18 +109,12 @@
 </template>
 
 <script setup>
-import { ref, computed, watch, onMounted } from "vue"
-import { useRoute, useRouter } from "vue-router"
-import { useStore } from "vuex"
+import { ref, computed } from "vue"
 const {
   windowSizeInCssForRef,
   windowSizeWhenDesignForRef,
 } = useSizeAdapt(1920, 968)
 
-const route = useRoute()
-const router = useRouter()
-const store = useStore()
-
 const emit = defineEmits(['close'])
 
 const title = computed(() => {
@@ -143,8 +141,9 @@ const layoutDataList = [
 ]
 
 const displayingHotspotIdx = ref(-1)
+const checkedHotspotIdx = ref(-1)
 
-
+const hotspotIdx = computed(() => displayingHotspotIdx.value > - 1 ? displayingHotspotIdx.value : checkedHotspotIdx.value)
 </script>
 
 <style lang="less" scoped>

File diff suppressed because it is too large
+ 8 - 15
src/components/CameraContent-1-2-2.vue


+ 4 - 2
src/components/CameraContent-1-2-3.vue

@@ -18,9 +18,11 @@
         <video
           src="@/assets/videos/camera-content-1-2-3.mp4"
           controls
-          playsinline
+          x5-playsinline="true"
+          playsinline="true"
           webkit-playsinline="true"
-          x5-video-player-type="h5"
+          x-webkit-airplay="true"
+          x5-video-player-type="h5-page"
           @play="stopBgAudio"
           @pause="startBgAudio"
         />

+ 2 - 1
src/components/CameraContent-1-3-1.vue

@@ -190,10 +190,11 @@ const activeTabIdx = ref(1)
         width: calc(405 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
       }
       .card-title {
-        margin-bottom: 35px;
+        margin-bottom: 30px;
         white-space: nowrap;
       }
       .text-indent {
+        padding-right: 20px;
         font-size: 20px;
         overflow: auto;
         max-height: 475px;

+ 1 - 0
src/components/CameraContent-2-1-1.vue

@@ -259,6 +259,7 @@ const title = '大运河的历史演变'
             line-height: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
 
             &.auto-content {
+              padding-right: 20px;
               max-height: 300px;
               overflow: auto;
             }

+ 1 - 3
src/components/CameraContent-2-1-3.vue

@@ -240,11 +240,9 @@ const tab1ContentPageNumber = ref(1)
 
           >p {
             flex: 1;
-            max-height: 490px;
+            max-height: calc(490 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
             overflow: auto;
             font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-            font-family: Source Han Sans SC, Source Han Sans SC;
-            font-weight: 300;
             color: #000000;
             line-height: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
             // letter-spacing: calc(4 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));

+ 0 - 2
src/components/CameraContent-3-1-1.vue

@@ -272,8 +272,6 @@ const activeTabIdx = ref(1)
       align-items: center;
       >p{
         width: calc(809 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-        max-height: calc(400 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-        overflow: auto;
         font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
         font-family: Source Han Sans CN, Source Han Sans CN;
         font-weight: 300;

+ 2 - 1
src/components/CameraContent-3-1-3.vue

@@ -228,7 +228,7 @@ const next = () => {
       justify-content: space-evenly;
       align-items: center;
       >.design-wrap-left {
-        width: calc(700 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        width: calc(720 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
         >.left-title {
           width: calc(579 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
           height: calc(62 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
@@ -243,6 +243,7 @@ const next = () => {
         >.left-text {
           font-family: 'SourceHanSansSC-Normal';
           margin-top: 25px;
+          padding-right: 20px;
           height: calc(300 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
           overflow: auto;
           font-family: 'SourceHanSansSC-Normal';

+ 3 - 8
src/components/CameraContent-3-2-3.vue

@@ -101,21 +101,16 @@ const title = '表演元曲的著名演员'
       top: 0;
       display: flex;
       align-items: center;
-      justify-content: space-between;
+      justify-content: center;
+      gap: 150px;
       padding: 0 97px 0 195px;
       width: 100%;
       height: 100%;
       box-sizing: border-box;
       background: url(@/assets/images/camera-content-3-1-3-design-bg.png) no-repeat center / cover;
       >.content-wrap__left{
-        display: flex;
-        flex-direction: column;
-        justify-content: center;
-        align-items: center;
-        height: 100%;
         >img{
-          flex: 0 0 auto;
-          height: 75%;
+          width: calc(520 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
         }
         >.img-title{
           margin-top: 0.5em;

+ 15 - 29
src/components/CharacterDesc.vue

@@ -22,21 +22,7 @@
 </template>
 
 <script setup>
-import { ref, computed, watch, onMounted } from "vue"
-import { useRoute, useRouter } from "vue-router"
-import { useStore } from "vuex"
-const {
-  windowSizeInCssForRef,
-  windowSizeWhenDesignForRef,
-} = useSizeAdapt()
-
 const emit = defineEmits(['close'])
-
-const route = useRoute()
-const router = useRouter()
-const store = useStore()
-
-
 </script>
 
 <style lang="less" scoped>
@@ -64,38 +50,38 @@ const store = useStore()
     left: 50%;
     top: 50%;
     transform: translate(-50%, -50%);
-    width: calc(1374 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    height: calc(550 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    width: 1374px;
+    height: 550px;
     background-image: url(@/assets/images/character-desc-bg.png);
     background-size: contain;
     background-repeat: no-repeat;
     background-position: center center;
-    padding-top: calc(117 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    padding-left: calc(510 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    padding-right: calc(105 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    padding-bottom: calc(155 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    padding-top: 117px;
+    padding-left: 510px;
+    padding-right: 105px;
+    padding-bottom: 155px;
     >.wrap-2{
       height: 100%;
       >h1{
-        font-size: calc(34 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-size: 34px;
         font-family: Source Han Serif SC, Source Han Serif SC;
         font-weight: 600;
         color: #CB9E44;
-        line-height: calc(40 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-        letter-spacing: calc(15 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-        margin-bottom: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        line-height: 40px;
+        letter-spacing: 15px;
+        margin-bottom: 21px;
       }
       >.splitter{
-        width: calc(743 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-        margin-bottom: calc(21 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        width: 743px;
+        margin-bottom: 21px;
       }
       >.desc{
-        height: calc(180 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-        font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        height: 180px;
+        font-size: 20px;
         font-family: Source Han Sans SC, Source Han Sans SC;
         font-weight: 400;
         color: #E8CF9A;
-        line-height: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        line-height: 30px;
         padding-right: 0.5em;
         overflow: auto;
       }

+ 31 - 13
src/components/GameEntryPage.vue

@@ -4,23 +4,29 @@
       class="return"
       @click="store.dispatch('closeGameEntryPage')"
     />
+    <img
+      class="game-entry-page__title"
+      src="@/assets/images/game-entry-page-title.png"
+      draggable="false"
+    >
     <div class="entry-list">
       <div
+        v-if="isGHG"
         class="entry-item"
-        @click="store.dispatch('openIframePage', {
+        @click="isGHG && store.dispatch('openIframePage', {
           url: 'https://houseoss.4dkankan.com/project/yzdyh-dadu/ghg/index.html',
           style: 'width: 100%; height: 100%'
         })"
       >
         <img
-          v-if="gameName !== '广寒宫'"
+          v-if="!isGHG"
           class=""
           src="@/assets/images/game-entry-jigsaw.png"
           alt=""
           draggable="false"
         >
         <img
-          v-if="gameName === '广寒宫'"
+          v-else
           class="highlight"
           src="@/assets/images/game-entry-jigsaw-highlight.png"
           alt=""
@@ -29,18 +35,19 @@
         <h3>广寒胜境</h3>
       </div>
       <div
+        v-if="isShip"
         class="entry-item"
-        @click="emit('playShipGame')"
+        @click="isShip && emit('playShipGame')"
       >
         <img
-          v-if="gameName !== '聊城古船'"
+          v-if="!isShip"
           class=""
           src="@/assets/images/game-entry-boat.png"
           alt=""
           draggable="false"
         >
         <img
-          v-if="gameName === '聊城古船'"
+          v-else
           class="highlight"
           src="@/assets/images/game-entry-boat-highlight.png"
           alt=""
@@ -49,21 +56,22 @@
         <h3>舟楫千里</h3>
       </div>
       <div
+        v-if="isDBG"
         class="entry-item"
-        @click="store.dispatch('openIframePage', {
+        @click="isDBG && store.dispatch('openIframePage', {
           url: $isMobile ? 'https://houseoss.4dkankan.com/project/yzdyh-dadu/duobaoge/mobile/index.html' : 'https://houseoss.4dkankan.com/project/yzdyh-dadu/duobaoge/index.html',
           style: 'width: 100%; height: 100%'
         })"
       >
         <img
-          v-if="gameName !== '多宝阁'"
+          v-if="!isDBG"
           class=""
           src="@/assets/images/game-entry-relic-show.png"
           alt=""
           draggable="false"
         >
         <img
-          v-if="gameName === '多宝阁'"
+          v-else
           class="highlight"
           src="@/assets/images/game-entry-relic-show-highlight.png"
           alt=""
@@ -86,6 +94,9 @@ const gameName = store.state.gameEntryPageAttrs.gameName
 
 const emit = defineEmits(['playShipGame'])
 
+const isGHG = gameName === '广寒宫'
+const isShip = gameName === '聊城古船'
+const isDBG = gameName === '多宝阁'
 </script>
 
 <style lang="less" scoped>
@@ -98,7 +109,14 @@ const emit = defineEmits(['playShipGame'])
   background-image: url(@/assets/images/game-entry-page-bg.jpg);
   background-size: cover;
   background-repeat: no-repeat;
-  background-position: center top;
+  background-position: center;
+  &__title {
+    position: absolute;
+    top: 20px;
+    left: 50%;
+    width: 1062px;
+    transform: translateX(-50%);
+  }
   >button.return{
     position: absolute;
     top: 68px;
@@ -108,13 +126,13 @@ const emit = defineEmits(['playShipGame'])
     background-image: url(@/assets/images/btn-return.png);
     background-size: cover;
     background-repeat: no-repeat;
-    background-position: center center;
+    background-position: center;
   }
   >.entry-list{
     position: absolute;
     left: 50%;
-    top: 60%;
-    transform: translate(-50%, -50%);
+    top: 320px;
+    transform: translateX(-50%);
     display: flex;
     justify-content: center;
     align-items: center;

File diff suppressed because it is too large
+ 37 - 21
src/components/HotspotDialog-1.vue


+ 50 - 10
src/components/MsgContent.vue

@@ -1,15 +1,7 @@
 <template>
   <div
     class="msg-content"
-    @click="() => {
-      if (_curIndex < list.length - 1) {
-        _curIndex += 1
-      } else {
-        _curIndex = 0
-        emits('end')
-      }
-      removeAudio()
-    }"
+    @click="handleContent"
   >
     <div
       class="msg-content__inner"
@@ -25,11 +17,21 @@
       class="msg-content__more"
       src="@/assets/images/tbn_nex.png"
     >
+
+    <div
+      v-if="showTips"
+      class="msg-content__tips"
+    >
+      <img
+        src="@/assets/images/hotspot-relic/tipsbox-min.png"
+      >
+      <p>点击对话框关闭对话</p>
+    </div>
   </div>
 </template>
 
 <script setup>
-import { computed, onBeforeUnmount, watch } from 'vue'
+import { computed, onBeforeUnmount, watch, ref } from 'vue'
 
 const {
   windowSizeInCssForRef,
@@ -38,6 +40,10 @@ const {
 const props = defineProps(['list', 'curIndex'])
 const emits = defineEmits(['update:cur-index', 'end', 'back'])
 
+const TIPS_KEY = 'ydd-msg-tips'
+
+const showTips = ref(!localStorage.getItem(TIPS_KEY))
+
 const _curIndex = computed({
   get() {
     return props.curIndex
@@ -69,6 +75,21 @@ const handleAudio = () => {
   }
 }
 
+const handleContent = () => {
+  if (_curIndex.value < props.list.length - 1) {
+    _curIndex.value += 1
+  } else {
+    _curIndex.value = 0
+    emits('end')
+  }
+  removeAudio()
+
+  if (showTips.value) {
+    showTips.value = false
+    localStorage.setItem(TIPS_KEY, 1)
+  }
+}
+
 onBeforeUnmount(() => {
   removeAudio()
 })
@@ -88,6 +109,25 @@ watch(curMsg, handleAudio, {
     font-size: 0;
     z-index: 3;
 
+    &__tips {
+      position: absolute;
+      top: -167px;
+      right: 109px;
+      width: 298px;
+
+      img {
+        width: inherit;
+      }
+      p {
+        position: absolute;
+        top: 20px;
+        left: 0;
+        right: 0;
+        font-size: 18px;
+        color: rgba(255,255,255,0.85);
+        text-align: center;
+      }
+    }
     &__inner {
       display: flex;
       flex-direction: column;

+ 7 - 3
src/components/StartUp.vue

@@ -40,9 +40,11 @@
       <video
         ref="videoEl"
         :src="$isMobile ? startVideoMobile : startVideo"
-        playsinline
+        playsinline="true"
         webkit-playsinline="true"
-        x5-video-player-type="h5"
+        x5-playsinline="true"
+        x-webkit-airplay="true"
+        x5-video-player-type="h5-page"
         @play="onVideoPlay"
         @ended="onVideoEnd"
       />
@@ -171,7 +173,8 @@ function onClickSkip() {
     background-size: cover;
     background-repeat: no-repeat;
     background-position: center center;
-    translate: -50% -50%;
+    transform: translate(-50%, -50%);
+    z-index: 1;
   }
   >img.person-animation{
     position: absolute;
@@ -185,6 +188,7 @@ function onClickSkip() {
     top: 0;
     width: 100%;
     height: 100%;
+    z-index: 1;
     >video{
       position: absolute;
       left: 0;

+ 129 - 21
src/components/UserGuide.vue

@@ -1,11 +1,38 @@
 <template>
   <div class="user-guide">
-    <video
-      v-if="showVideo"
-      autoplay
-      src="@/assets/videos/guide.mp4"
-      @ended="showVideo = false"
-    />
+    <template v-if="showVideo">
+      <video
+        ref="videoRef"
+        autoplay
+        src="@/assets/videos/guide.mp4"
+        x5-playsinline="true"
+        playsinline="true"
+        webkit-playsinline="true"
+        x-webkit-airplay="true"
+        x5-video-player-type="h5-page"
+        @play="showVideoPlay = false"
+        @ended="showVideo = false"
+      />
+
+      <img
+        v-if="$isMobile && showVideoPlay"
+        class="play-icon"
+        src="@/assets/images/play.png"
+        @click="() => {
+          videoRef?.play()
+          showVideoPlay = false
+        }"
+      >
+
+      <img
+        class="video-skip"
+        src="@/assets/images/startup-video-skip.png"
+        @click="() => {
+          showVideo = false
+          showVideoPlay = false
+        }"
+      >
+    </template>
 
     <template v-else>
       <div
@@ -27,6 +54,14 @@
             </div>
           </div>
 
+          <div class="guide-game">
+            <div
+              class="left-line"
+            >
+              游戏入口
+            </div>
+          </div>
+
           <div class="guide-guide">
             <div
               class="left-line"
@@ -46,6 +81,20 @@
           </div>
         </div>
 
+        <div class="guide-box">
+          <div class="guide-box__contain">
+            <img
+              src="https://4dkk.4dage.com/720yun_fd_manage/fodder/20231227_155535175.png"
+            >
+          </div>
+
+          <div
+            class="left-line"
+          >
+            <span>探索文物</span>
+          </div>
+        </div>
+
         <template v-if="curStep > 5">
           <div
             class="character"
@@ -66,14 +115,14 @@
         </template>
 
         <template v-if="curStep > 2">
-          <div
-            class="top-line"
-            style="left: 382px; bottom: 520px;"
-          >
-            阅读历史
-          </div>
           <div class="guide-menu">
             营都人员与机构
+
+            <div
+              class="top-line"
+            >
+              阅读历史
+            </div>
           </div>
         </template>
 
@@ -113,6 +162,8 @@ import { onMounted, ref, inject } from "vue"
 const curStep = ref(0)
 const guideTabStyle = ref('')
 const showVideo = ref(true)
+const showVideoPlay = ref(true)
+const videoRef = ref()
 const $isMobile = inject('$isMobile')
 const emits = defineEmits(['close'])
 
@@ -135,6 +186,22 @@ const handleClose = () => {
 </script>
 
 <style lang="less" scoped>
+.video-skip {
+  position: absolute;
+  right: 43px;
+  bottom: 20px;
+  width: 291px;
+  cursor: pointer;
+  z-index: 1;
+}
+.play-icon {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 120px;
+  transform: translate(-50%, -50%);
+  z-index: 1;
+}
 .user-guide {
   .character {
     position: absolute;
@@ -166,14 +233,7 @@ const handleClose = () => {
     font-family: "Source Han Sans SC Regular" !important;
   }
 }
-@keyframes character-default-animation {
-  0% {
-    translate: 0 0;
-  }
-  100% {
-    translate: -100% 0;
-  }
-}
+
 .guide-tab {
   display: none;
   position: absolute;
@@ -211,6 +271,11 @@ const handleClose = () => {
   box-sizing: border-box;
   font-family: Source Han Serif CN;
   background: url('@/assets/images/camera-btn-1-1-2-active.png') no-repeat center / contain;
+
+  .top-line {
+    top: -130px;
+    left: 55px;
+  }
 }
 .qhcj {
   position: absolute;
@@ -222,6 +287,16 @@ const handleClose = () => {
   .top-line {
     bottom: 0;
   }
+  &::after {
+    content: '';
+    position: absolute;
+    left: -40px;
+    bottom: -230px;
+    width: 120px;
+    height: 120px;
+    border-radius: 4px;
+    box-shadow: 0px 0px 5px 0px #FFE88B;
+  }
 }
 .guide-home {
   position: absolute;
@@ -236,10 +311,18 @@ const handleClose = () => {
   position: absolute;
   width: 77px;
   height: 77px;
-  top: 128px;
+  top: 213px;
   right: 51px;
   background: url('@/assets/images/guide/tbn_help-min.png') no-repeat center / cover;
 }
+.guide-game {
+  position: absolute;
+  width: 77px;
+  height: 77px;
+  top: 128px;
+  right: 51px;
+  background: url('@/assets/images/btn-game-entry-page-1.png') no-repeat center / cover;
+}
 .guide-dot {
   position: absolute;
   top: 118px;
@@ -249,6 +332,31 @@ const handleClose = () => {
   background: url('@/assets/images/guide/Dots.png')  no-repeat center / contain;
   z-index: 1;
 }
+.guide-box {
+  position: absolute;
+  top: 188px;
+  right: 850px;
+  width: 60px;
+  height: 60px;
+  z-index: 1;
+
+  &__contain {
+    position: relative;
+    width: inherit;
+    height: inherit;
+    overflow: hidden;
+  }
+  img {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: inherit;
+    animation-name: hotspot-icon-animation;
+    animation-timing-function: steps(24, end);
+    animation-duration: 1s;
+    animation-iteration-count: infinite;
+  }
+}
 .top-line {
   position: absolute;
   left: 50%;

+ 1 - 0
src/store/index.js

@@ -102,6 +102,7 @@ export default createStore({
   actions: {
     openIframePage({ commit }, attrs) {
       commit('setIframeAttrs', attrs)
+      commit('setGameEntryPageAttrs', false)
     },
     openGameEntryPage({ commit }, attrs) {
       commit('setGameEntryPageAttrs', attrs)

+ 8 - 6
src/useFunctions/useSmoothSwipe.js

@@ -41,8 +41,8 @@ export default function useSmoothSwipe({
   viewportWidth = document.documentElement.clientWidth,
   speedFactor = 1,
   damping = 0.003, // 阻尼
+  dontHandlerMobile = false, // 不处理移动端
   enableAutoMoving = false,
-  initTranslateLength = 0
 } = {}) {
   const isOperating = ref(false)
   const hasOperatedThisTime = ref(false)
@@ -50,7 +50,7 @@ export default function useSmoothSwipe({
   let lastMoveEventTimeStamp = 0
   let lastCursorPos = 0
   let moveSpeed = ref(0)
-  let translateLength = ref(initTranslateLength)
+  let translateLength = ref(0)
   let maxTranslateLengthInner = Infinity
   let isAutoMoving = ref(false)
   let beginAutoMoveIntervalId = null
@@ -264,10 +264,12 @@ export default function useSmoothSwipe({
         v.addEventListener('mouseleave', onMouseLeave)
         v.addEventListener('mousemove', onMouseMove)
         v.addEventListener('mouseup', onMouseUp)
-        v.addEventListener('touchstart', onTouchStart)
-        v.addEventListener('touchmove', onTouchMove)
-        v.addEventListener('touchend', onTouchEnd)
-        v.addEventListener('touchcancel', onTouchCancel)
+        if (!dontHandlerMobile) {
+          v.addEventListener('touchstart', onTouchStart)
+          v.addEventListener('touchmove', onTouchMove)
+          v.addEventListener('touchend', onTouchEnd)
+          v.addEventListener('touchcancel', onTouchCancel)
+        }
       }
     }, {
       immediate: true,

+ 4 - 2
src/views/EpilogueView.vue

@@ -13,9 +13,11 @@
         class="epilogue-video"
         src="@/assets/videos/epilogue.mp4"
         autoplay
-        playsinline
+        x5-playsinline="true"
+        playsinline="true"
         webkit-playsinline="true"
-        x5-video-player-type="h5"
+        x-webkit-airplay="true"
+        x5-video-player-type="h5-page"
         @ended="isShowVideo = false"
       />
     </transition>

+ 80 - 24
src/views/HomeView.vue

@@ -25,30 +25,67 @@
         >
       </div>
     </transition>
-    <transition
-      v-for="idx in 3"
-      :key="idx"
-      name="fade-in-out"
-    >
-      <div
-        v-if="hoveringEntryIdx === idx"
-        :class="`scene-preview scene-preview-${idx}`"
-        @click="goToDetail(idx)"
+    <template v-if="!$isMobile">
+      <transition
+        v-for="idx in 3"
+        :key="idx"
+        name="fade-in-out"
       >
-        <img
-          class="bg"
-          :src="require(`@/assets/images/scene-${idx}-preview.jpg`)"
-          alt=""
-          draggable="false"
+        <div
+          v-if="hoveringEntryIdx === idx"
+          :class="`scene-preview scene-preview-${idx}`"
+          @click="goToDetail(idx)"
         >
-        <img
-          class="title"
-          :src="require(`@/assets/images/scene-preview-title-${idx}.png`)"
-          alt=""
-          draggable="false"
+          <img
+            class="bg"
+            :src="require(`@/assets/images/scene-${idx}-preview.jpg`)"
+            alt=""
+            draggable="false"
+          >
+          <img
+            class="title"
+            :src="require(`@/assets/images/scene-preview-title-${idx}.png`)"
+            alt=""
+            draggable="false"
+          >
+        </div>
+      </transition>
+    </template>
+    <template v-else-if="store.state.haveShownStartUp">
+      <Swiper
+        class="scene-preview swiper-scene-preview"
+        :autoplay="{
+          delay: 3000,
+          disableOnInteraction: false
+        }"
+        auto-height
+        @slide-change="(e) => {
+          hoveringEntryIdx = e.activeIndex + 1
+        }"
+        @swiper="e => swiper = e"
+      >
+        <SwiperSlide
+          v-for="idx in 3"
+          :key="idx"
+          :class="`scene-preview-${idx}`"
+          @click="goToDetail(idx)"
         >
-      </div>
-    </transition>
+          <img
+            class="bg"
+            :src="require(`@/assets/images/scene-${idx}-preview.jpg`)"
+            alt=""
+            draggable="false"
+          >
+          <img
+            class="title"
+            :src="require(`@/assets/images/scene-preview-title-${idx}.png`)"
+            alt=""
+            draggable="false"
+          >
+        </SwiperSlide>
+      </Swiper>
+    </template>
+
     <button
       class="logo"
       @click="onClickLogo"
@@ -97,12 +134,14 @@ import { ref, onMounted, inject, watch } from "vue"
 import { useRouter } from "vue-router"
 import { useStore } from "vuex"
 import StartUp from '@/components/StartUp.vue'
+import { Swiper, SwiperSlide } from "swiper/vue"
 
 const {
   windowSizeInCssForRef,
   windowSizeWhenDesignForRef,
 } = useSizeAdapt()
 
+let swiper = null
 const $isMobile = inject('$isMobile')
 const stopBgAudio = inject('stopBgAudio')
 const router = useRouter()
@@ -138,6 +177,7 @@ const handleGroup = (idx) => {
       }
     })
   } else {
+    swiper?.slideTo(idx - 1)
     hoveringEntryIdx.value = idx
   }
 }
@@ -157,10 +197,23 @@ const goToDetail = (idx) => {
 const handleHover = (num) => {
   const _num = Math.max(hoveringEntryIdx.value + num, 1)
   hoveringEntryIdx.value = _num > 3 ? 3 : _num
+  swiper?.slideTo(_num - 1)
 }
 </script>
 
 <style lang="less" scoped>
+.swiper-scene-preview {
+  .title {
+    position: absolute;
+    z-index: 1;
+  }
+  .bg {
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+    object-position: center;
+  }
+}
 .mobile-helper {
   position: absolute;
   top: 50%;
@@ -181,6 +234,8 @@ const handleHover = (num) => {
 }
 .icon-left {
   left: 0;
+  margin-left: constant(safe-area-inset-left);
+  margin-left: env(safe-area-inset-left);
 }
 .icon-right {
   right: 0;
@@ -234,21 +289,21 @@ const handleHover = (num) => {
       position: absolute;
     }
   }
-  >.scene-preview-1{
+  .scene-preview-1{
     >img.title{
       top: calc(209 / 1080 * 100vh);
       left: calc(168 / 1920 *100vw);
       height: calc(257 / 1080 * 100vh);
     }
   }
-  >.scene-preview-2{
+  .scene-preview-2{
     >img.title{
       top: calc(325 / 1080 * 100vh);
       right: calc(123 / 1920 *100vw);
       height: calc(297 / 1080 * 100vh);
     }
   }
-  >.scene-preview-3{
+  .scene-preview-3{
     >img.title{
       top: calc(286 / 1080 * 100vh);
       left: calc(864 / 1920 *100vw);
@@ -260,6 +315,7 @@ const handleHover = (num) => {
     position: absolute;
     width: 100%;
     bottom: 50px;
+    z-index: 1;
     >button.scene-entry.entry-1{
       position: absolute;
       left: 20%;

+ 31 - 28
src/views/PanoView.vue

@@ -266,10 +266,12 @@
               showScene1Camera2To3Video ? '@/assets/videos/scene-2-camera-2.mp4' :
               '@/assets/videos/scene-3-camera-1.mp4'
             )"
-            playsinline
             autoplay
+            x5-playsinline="true"
+            playsinline="true"
             webkit-playsinline="true"
-            x5-video-player-type="h5"
+            x-webkit-airplay="true"
+            x5-video-player-type="h5-page"
             style="position: relative; z-index: -2; width: 100vw; height: 100vh; object-fit: cover;"
           />
           <div
@@ -321,11 +323,19 @@
       ref="sceneIntrovideoStartEl"
       class="scene-intro-video scene-intro-video-start"
       :src="require(`@/assets/videos/scene-${sceneIdx + 1}-introduction.mp4`)"
-      playsinline
+      x5-playsinline="true"
+      playsinline="true"
       webkit-playsinline="true"
-      x5-video-player-type="h5"
+      x-webkit-airplay="true"
+      x5-video-player-type="h5-page"
       @ended="onPlayedFirstSceneIntroVideoEnded"
     />
+    <audio
+      v-show="isShowSceneIntroVideoStart"
+      ref="sceneIntroaudioStartEl"
+      :src="require(`@/assets/audios/camera-intro-${sceneIdx + 1}-${cameraIdx + 1}.mp3`)"
+      @ended="clearCameraIntroMedia"
+    />
     <button
       v-show="isShowSceneIntroVideoStart"
       class="skip-scene-intro"
@@ -369,7 +379,10 @@
     v-if="store.state.gameEntryPageAttrs"
     style="z-index: 998;"
     class="game-entry-page"
-    @playShipGame="showShipGame = true"
+    @play-ship-game="() => {
+      showShipGame = true
+      store.dispatch('closeGameEntryPage')
+    }"
   />
 
   <div
@@ -614,7 +627,7 @@ function onClickCharacter(anType) {
       duration = 4000
       break
     case 3:
-      duration = 5000
+      duration = 3000
       break
     case 4:
       duration = 5000
@@ -666,7 +679,6 @@ const cameraIntroText = computed(() => {
   return sceneTree[sceneIdx.value].cameraList[cameraIdx.value].desc
 })
 let cameraIntroAudioTimeoutId = null
-let cameraIntroAudio = null
 
 const showScene0Camera1To2Video = ref(false)
 const showScene0Camera2To3Video = ref(false)
@@ -712,10 +724,7 @@ watch(cameraIdx, (vNew, pVal) => {
     isShowCameraIntro.value = true
     charactorSpeackPositionLeft.value = !charactorSpeackPositionLeft.value
     cameraIntroAudioTimeoutId = setTimeout(() => {
-      cameraIntroAudio?.pause()
-      cameraIntroAudio = new Audio(require(`@/assets/audios/camera-intro-${sceneIdx.value + 1}-${cameraIdx.value + 1}.mp3`))
-      cameraIntroAudio.play()
-      cameraIntroAudio.addEventListener('ended', clearCameraIntroMedia)
+      sceneIntroaudioStartEl.value.play()
     }, 1000)
   }
 })
@@ -723,7 +732,7 @@ watch(cameraIdx, (vNew, pVal) => {
 // 跳过按钮 功能
 function skipCameraIntro(showAction) {
   clearTimeout(cameraIntroAudioTimeoutId)
-  cameraIntroAudio?.pause()
+  sceneIntroaudioStartEl.value?.pause()
   clearCameraIntroMedia(showAction)
 }
 onUnmounted(() => {
@@ -739,6 +748,7 @@ onBeforeRouteUpdate(() => {
 const isShowSceneIntroVideoStart = ref(false)
 const isShowSceneIntroVideoEnd = ref(false)
 const sceneIntrovideoStartEl = ref(null)
+const sceneIntroaudioStartEl = ref(null)
 const sceneIntrovideoEndEl = ref(null)
 
 /**
@@ -958,7 +968,7 @@ watch(() => store.getters.iframeAttrs, (v) => {
   }
 })
 
-const isShowMenu = ref(false)
+const isShowMenu = ref($isMobile)
 const isShowHotspotDetail = ref(false)
 const isShowHotspotDetail2 = ref(!!route.query.hotspot)
 const isShowHotspotDetail3 = ref(false)
@@ -1230,8 +1240,8 @@ onMounted(() => {
       @frame-num-1: 60;
       @duration-2: 4s;
       @frame-num-2: 96;
-      @duration-3: 5s;
-      @frame-num-3: 121;
+      @duration-3: 3s;
+      @frame-num-3: 72;
       // @duration-4: 3s;
       // @frame-num-4: 72;
       @duration-5: 3.12s;
@@ -1247,7 +1257,9 @@ onMounted(() => {
         cursor: pointer;
         >.default-frames{
           position: absolute;
+          top: 0;
           left: 0;
+          width: 38400px;
           height: 100%;
           will-change: transform;
           animation-name: character-default-animation;
@@ -1267,6 +1279,7 @@ onMounted(() => {
           }
         }
         >.frames-2{
+          width: 61440px;
           transition-duration: @duration-2;
           transition-timing-function: steps(@frame-num-2, jump-end);
           &.state2 {
@@ -1274,6 +1287,7 @@ onMounted(() => {
           }
         }
         >.frames-3{
+          width: 46080px;
           transition-duration: @duration-3;
           transition-timing-function: steps(@frame-num-3, jump-end);
           &.state2 {
@@ -1472,16 +1486,13 @@ onMounted(() => {
       left: 0;
 
       img {
-        animation-duration: 3;
+        animation-duration: 3s;
         animation-timing-function: steps(72);
       }
     }
     img {
       height: 100%;
-      animation-name: character-default-animation;
-      animation-timing-function: steps(121);
-      animation-duration: 8s;
-      animation-iteration-count: infinite;
+      animation: character-default-animation steps(121) 8s infinite;
     }
   }
    >.text-wrap{
@@ -1625,12 +1636,4 @@ onMounted(() => {
    * end of 场景切换过渡
    */
 }
-@keyframes character-default-animation {
-  0% {
-    translate: 0 0;
-  }
-  100% {
-    translate: -100% 0;
-  }
-}
 </style>

+ 40 - 32
src/views/RelicList.vue

@@ -61,7 +61,8 @@
             class="name"
             :class="{
               wide: item['名称'].length > 11,
-              smallFontSize: item['名称'].length > 18
+              smallFontSize: item['名称'].length > 18,
+              smFontSize: item['序号'] === 95
             }"
             :title="item['名称']"
             v-html="item['名称']"
@@ -79,6 +80,7 @@
       </div>
     </div>
   </div>
+  <div style="height: 100vh;" />
 </template>
 
 <script setup>
@@ -199,10 +201,10 @@ function getRelicThumbUrl(idx) {
 const listEl = ref(null)
 let scrollLeft = Number(localStorage.getItem(SCROLL_KEY) || 0)
 const { width: listWidth, height: listHeight } = useElementSize(listEl)
-const { hasOperatedThisTime, updateWidth, updateTranslateLength } = useSmoothSwipe({
+const { translateLength, hasOperatedThisTime, updateWidth, updateTranslateLength } = useSmoothSwipe({
   scrollTargetRef: listEl,
   viewportWidth: listWidth,
-  initTranslateLength: scrollLeft,
+  dontHandlerMobile: true
 })
 watch(relicData, (vNew) => {
   nextTick(() => {
@@ -234,6 +236,7 @@ watch(cascaderValue, val => {
     }
   })
   updateTranslateLength(0)
+  localStorage.setItem(SCROLL_KEY, 0)
 })
 
 router.beforeEach((to) => {
@@ -244,7 +247,7 @@ router.beforeEach((to) => {
 
 onMounted(() => {
   if (scrollLeft) {
-    listEl.value.scrollLeft = scrollLeft
+    updateTranslateLength(scrollLeft)
   }
 })
 
@@ -257,7 +260,7 @@ const handleScroll = debounce(() => {
 @page-height-design-px: 970;
 
 .relic-list {
-  height: 100%;
+  height: 100vh;
   background-image: url(@/assets/images/relic-list-bg.jpg);
   background-size: cover;
   background-repeat: no-repeat;
@@ -265,10 +268,10 @@ const handleScroll = debounce(() => {
 
   >button.return {
     position: absolute;
-    width: 58px;
-    height: 58px;
-    left: 42px;
-    top: 68px;
+    width: calc(58 / @page-height-design-px * 100vh);
+    height: calc(58 / @page-height-design-px * 100vh);
+    left: calc(42 / @page-height-design-px * 100vh);
+    top: calc(68 / @page-height-design-px * 100vh);
     background-image: url(@/assets/images/btn-return.png);
     background-size: contain;
     background-repeat: no-repeat;
@@ -278,10 +281,11 @@ const handleScroll = debounce(() => {
   :deep {
     .el-cascader {
       position: absolute;
-      width: 200px;
-      height: 58px;
-      left: 160px;
-      top: 68px;
+      width: calc(200 / @page-height-design-px * 100vh);
+      height: calc(58 / @page-height-design-px * 100vh);
+      left: calc(160 / @page-height-design-px * 100vh);
+      top: calc(68 / @page-height-design-px * 100vh);
+      z-index: 1;
 
       .el-input {
         height: 100%;
@@ -296,7 +300,7 @@ const handleScroll = debounce(() => {
 
           .el-input__inner {
             height: 100%;
-            font-size: 30px;
+            font-size: calc(30 / @page-height-design-px * 100vh);
             text-align: center;
             font-family: 'SourceHanSerifCN-Heavy';
             color: #6A3906;
@@ -307,8 +311,8 @@ const handleScroll = debounce(() => {
 
         }
         .icon-arrow-down {
-          font-size: 24px;
-          margin-top: 10px;
+          font-size: calc(24 / @page-height-design-px * 100vh);
+          margin-top: calc(10 / @page-height-design-px * 100vh);
         }
 
       }
@@ -321,44 +325,45 @@ const handleScroll = debounce(() => {
 
   >.search-ui {
     position: absolute;
-    top: 65px;
-    right: 27px;
-    width: 406px;
-    height: 62px;
+    top: calc(65 / @page-height-design-px * 100vh);
+    right: calc(27 / @page-height-design-px * 100vh);
+    width: calc(406 / @page-height-design-px * 100vh);
+    height: calc(62 / @page-height-design-px * 100vh);
     background-image: url(@/assets/images/search-bg.png);
     background-size: cover;
     background-repeat: no-repeat;
     background-position: center center;
+    z-index: 1;
 
     >input {
       position: absolute;
       left: 50px;
       top: 50%;
       transform: translateY(-50%);
-      height: 35px;
-      width: 250PX;
-      font-size: 24px;
+      height: calc(35 / @page-height-design-px * 100vh);
+      width: calc(250 / @page-height-design-px * 100vh);
+      font-size: calc(24 / @page-height-design-px * 100vh);
       font-family: Source Han Sans CN, Source Han Sans CN;
       font-weight: 400;
       color: rgba(255, 255, 255, 0.7);
-      line-height: 28px;
+      line-height: calc(28 / @page-height-design-px * 100vh);
 
       &::placeholder {
-        font-size: 24px;
+        font-size: calc(24 / @page-height-design-px * 100vh);
         font-family: Source Han Sans CN, Source Han Sans CN;
         font-weight: 400;
         color: rgba(255, 255, 255, 0.3);
-        line-height: 28px;
+        line-height: calc(28 / @page-height-design-px * 100vh);
       }
     }
 
     >button.search {
       position: absolute;
-      width: 31px;
-      height: 31px;
+      width: calc(31 / @page-height-design-px * 100vh);
+      height: calc(31 / @page-height-design-px * 100vh);
       position: absolute;
       top: 50%;
-      right: 53px;
+      right: calc(53 / @page-height-design-px * 100vh);
       transform: translateY(-50%);
       background-image: url(@/assets/images/icon-search.png);
       background-size: cover;
@@ -371,7 +376,7 @@ const handleScroll = debounce(() => {
     position: absolute;
     left: 0;
     top: 55%;
-    translate: 0 -50%;
+    transform: translateY(-50%);
     width: 100%;
     height: calc(650 / @page-height-design-px * 100vh);
     background-size: auto 100%;
@@ -456,13 +461,16 @@ const handleScroll = debounce(() => {
           padding-right: calc(20 / @page-height-design-px * 100vh * 0.83);;
           font-size: calc(14 / @page-height-design-px * 100vh * 0.83);
         }
+        >.name.smFontSize {
+          font-size: calc(14 / @page-height-design-px * 100vh * 0.83);
+        }
         >img {
           position: absolute;
           left: 50%;
-          translate: -50% 0;
+          transform: translateX(-50%) scale(calc(v-bind('windowHeight') / @page-height-design-px));
           object-fit: contain;
-          scale: calc(v-bind('windowHeight') / @page-height-design-px);
           transform-origin: center bottom;
+          pointer-events: none;
         }
       }
       >.relic-item.isOdd{

+ 57 - 11
src/views/ShipGame/ShipGameView.vue

@@ -13,7 +13,7 @@
     >
       <img
         class="logo"
-        src="@/assets/images/ship-game/Group 493-min.png"
+        src="@/assets/images/ship-game/Group485-min.png"
       >
 
       <p>
@@ -29,7 +29,7 @@
       <img
         class="logo2"
         draggable="false"
-        src="@/assets/images/ship-game/Group 493-min.png"
+        src="@/assets/images/ship-game/Group485-min.png"
       >
       <p class="tips">
         长按下方部件并拖动到正确位置,完成船只拼图
@@ -102,23 +102,49 @@
         </div>
       </div>
 
-      <video
-        v-if="showVideo"
-        class="video"
-        autoplay
-        src="@/assets/videos/ship-game/end.mp4"
-        @ended="back"
-      />
+      <template v-if="showVideo">
+        <video
+          ref="videoRef"
+          class="video"
+          autoplay
+          x5-playsinline="true"
+          playsinline="true"
+          webkit-playsinline="true"
+          x-webkit-airplay="true"
+          x5-video-player-type="h5-page"
+          src="@/assets/videos/ship-game/end.mp4"
+          @play="() => {
+            showVideoPlay = false
+          }"
+          @ended="back"
+        />
+
+        <div
+          v-if="showVideoPlay"
+          class="play-icon"
+        >
+          <img
+            v-if="$isMobile"
+            src="@/assets/images/play.png"
+            @click="() => {
+              videoRef?.play()
+            }"
+          >
+        </div>
+      </template>
     </template>
   </div>
 </template>
 
 <script setup>
-import { ref, watch } from 'vue'
+import { ref, watch, inject } from 'vue'
 // import { useRouter } from 'vue-router'
 import { Container, Draggable } from "vue3-smooth-dnd"
 
 // const router = useRouter()
+const $isMobile = inject('$isMobile')
+const showVideoPlay = ref(true)
+const videoRef = ref(null)
 const showBanner = ref(false)
 const showVideo = ref(false)
 const {
@@ -192,6 +218,22 @@ const back = () => {
 </script>
 
 <style lang="less" scoped>
+.play-icon {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: rgba(0, 0, 0, .6);
+  z-index: 10;
+
+  img {
+    width: 120px;
+  }
+}
 .drag-class {
   &.module1 {
     width: calc(986 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
@@ -271,7 +313,7 @@ const back = () => {
     position: absolute;
     top: 76px;
     left: 62px;
-    width: 460px;
+    width: 383px;
   }
   .tips {
     position: absolute;
@@ -339,6 +381,7 @@ const back = () => {
       }
       img {
         cursor: pointer;
+        pointer-events: none;
       }
       span {
         position: absolute;
@@ -363,6 +406,9 @@ const back = () => {
       cover;
     z-index: 5;
 
+    .logo {
+      width: 383px;
+    }
     p {
       padding: 20px 0 120px;
       width: 714px;

+ 32 - 0
yarn.lock

@@ -983,6 +983,13 @@
   dependencies:
     regenerator-runtime "^0.14.0"
 
+"@babel/runtime@^7.17.2":
+  version "7.23.9"
+  resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7"
+  integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==
+  dependencies:
+    regenerator-runtime "^0.14.0"
+
 "@babel/template@^7.22.15", "@babel/template@^7.22.5":
   version "7.22.15"
   resolved "https://registry.npmmirror.com/@babel/template/-/template-7.22.15.tgz"
@@ -2670,6 +2677,11 @@ copy-anything@^2.0.1:
   dependencies:
     is-what "^3.14.1"
 
+copy-text-to-clipboard@^3.0.1:
+  version "3.2.0"
+  resolved "https://registry.npmmirror.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz#0202b2d9bdae30a49a53f898626dcc3b49ad960b"
+  integrity sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==
+
 copy-webpack-plugin@^9.0.1:
   version "9.1.0"
   resolved "https://registry.npmmirror.com/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz"
@@ -2689,6 +2701,11 @@ core-js-compat@^3.31.0, core-js-compat@^3.33.1, core-js-compat@^3.8.3:
   dependencies:
     browserslist "^4.22.1"
 
+core-js@^3.11.0:
+  version "3.35.1"
+  resolved "https://registry.npmmirror.com/core-js/-/core-js-3.35.1.tgz#9c28f8b7ccee482796f8590cc8d15739eaaf980c"
+  integrity sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw==
+
 core-js@^3.8.3:
   version "3.33.3"
   resolved "https://registry.npmmirror.com/core-js/-/core-js-3.33.3.tgz"
@@ -4646,6 +4663,11 @@ multicast-dns@^7.2.5:
     dns-packet "^5.2.2"
     thunky "^1.0.2"
 
+mutation-observer@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/mutation-observer/-/mutation-observer-1.0.3.tgz#42e9222b101bca82e5ba9d5a7acf4a14c0f263d0"
+  integrity sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==
+
 mz@^2.4.0:
   version "2.7.0"
   resolved "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz"
@@ -6324,6 +6346,16 @@ vary@~1.1.2:
   resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz"
   integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
 
+vconsole@^3.15.1:
+  version "3.15.1"
+  resolved "https://registry.npmmirror.com/vconsole/-/vconsole-3.15.1.tgz#569a8ab15f353259527bbcf004f02946b4482cff"
+  integrity sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==
+  dependencies:
+    "@babel/runtime" "^7.17.2"
+    copy-text-to-clipboard "^3.0.1"
+    core-js "^3.11.0"
+    mutation-observer "^1.0.3"
+
 viewerjs@^1.11.6, viewerjs@^1.9.0:
   version "1.11.6"
   resolved "https://registry.npmmirror.com/viewerjs/-/viewerjs-1.11.6.tgz"