Przeglądaj źródła

feat: 五卅运动100周年

chenlei 7 miesięcy temu
rodzic
commit
1a22560a7e
56 zmienionych plików z 1564 dodań i 4 usunięć
  1. 2 0
      README.md
  2. 1 0
      components.d.ts
  3. 2 0
      package.json
  4. BIN
      public/fonts/SourceHanSansCN-Heavy.otf
  5. BIN
      public/images/wsyd/Volume btn_off.png
  6. BIN
      public/images/wsyd/Volume btn_on.png
  7. BIN
      public/images/wsyd/auto-suspend.png
  8. BIN
      public/images/wsyd/auto.png
  9. BIN
      public/images/wsyd/dollhouse.png
  10. BIN
      public/images/wsyd/enlarge_on.png
  11. BIN
      public/images/wsyd/floor.png
  12. BIN
      public/images/wsyd/hotlist.png
  13. BIN
      public/images/wsyd/inside.png
  14. BIN
      public/images/wsyd/like.png
  15. BIN
      public/images/wsyd/menu-bg.jpg
  16. BIN
      public/images/wsyd/menu-bg2.jpg
  17. BIN
      public/images/wsyd/menu-img.png
  18. BIN
      public/images/wsyd/narrow_off.png
  19. BIN
      public/images/wsyd/pause.png
  20. BIN
      public/images/wsyd/play.png
  21. BIN
      public/images/wsyd/share.png
  22. BIN
      public/images/wsyd/unlike.png
  23. BIN
      public/images/wsyd/viewer.png
  24. 7 0
      src/el.scss
  25. 196 0
      src/hotspot/views/hotspot/index.wsyd.scss
  26. 279 0
      src/hotspot/views/hotspot/index.wsyd.vue
  27. 4 0
      src/index/app.scss
  28. BIN
      src/index/assets/images/wsyd/hot-bg-min.jpg
  29. BIN
      src/index/assets/images/wsyd/hot-bg.png
  30. BIN
      src/index/assets/images/wsyd/mobile/hot-bg.jpg
  31. BIN
      src/index/assets/images/wsyd/sidebar-bg-min.png
  32. BIN
      src/index/assets/images/wsyd/sidebar-btn.png
  33. BIN
      src/index/assets/images/wsyd/sidebar-close-min.png
  34. BIN
      src/index/assets/images/wsyd/sidebar-img.png
  35. 21 0
      src/index/router/index.wsyd.ts
  36. 6 0
      src/index/utils/index.ts
  37. BIN
      src/index/views/cover/images/bg.jpg
  38. BIN
      src/index/views/cover/images/bg2.png
  39. BIN
      src/index/views/cover/images/btn.png
  40. BIN
      src/index/views/cover/images/guide.png
  41. BIN
      src/index/views/cover/images/mobile/bg.jpg
  42. BIN
      src/index/views/cover/images/mobile/bg2.png
  43. BIN
      src/index/views/cover/images/title.png
  44. 82 0
      src/index/views/cover/index.scss
  45. 37 0
      src/index/views/cover/index.vue
  46. 96 0
      src/index/views/home/components/article-popup/index.scss
  47. 89 0
      src/index/views/home/components/article-popup/index.vue
  48. 2 2
      src/index/views/home/components/guide/index.scss
  49. 150 0
      src/index/views/home/components/hot-spot-list/index.wsyd.scss
  50. 24 0
      src/index/views/home/components/hot-spot-list/index.wsyd.tsx
  51. 193 0
      src/index/views/home/components/menu/index.wsyd.scss
  52. 151 0
      src/index/views/home/components/menu/index.wsyd.vue
  53. 60 0
      src/index/views/home/components/popup/index.wsyd.scss
  54. 16 0
      src/index/views/home/components/popup/index.wsyd.tsx
  55. 135 0
      src/index/views/home/index.wsyd.tsx
  56. 11 2
      vite.config.ts

+ 2 - 0
README.md

@@ -1,3 +1,5 @@
+BJS2503126-1 中国共产党第一次全国代表大会纪念馆-五卅运动云展览采集
+
 ### 初始化
 
 ```bash

+ 1 - 0
components.d.ts

@@ -9,6 +9,7 @@ declare module 'vue' {
   export interface GlobalComponents {
     ElDialog: typeof import('element-plus/es')['ElDialog']
     ElImage: typeof import('element-plus/es')['ElImage']
+    ElPopover: typeof import('element-plus/es')['ElPopover']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']

+ 2 - 0
package.json

@@ -7,6 +7,8 @@
     "serve": "cross-env VITE_APP_TITLE=大理洱海科普馆 VITE_APP_HOT_DOMAIN=./hotspot.html vite",
     "build:test": "cross-env VITE_APP_TITLE=大理洱海科普馆 run-p type-check \"build-only {@}\" --",
     "push:test": "cross-env node ./scripts/publish.js",
+    "serve:wsyd": "cross-env VITE_APP_TITLE=中共一大纪念馆专题展厅 VITE_APP_SCENE=wsyd VITE_APP_HOT_DOMAIN=./hotspot.html vite",
+    "build:wsyd:test": "cross-env VITE_APP_TITLE=中共一大纪念馆专题展厅 VITE_APP_SCENE=wsyd run-p type-check \"build-only {@}\" --",
     "preview": "vite preview",
     "build-only": "vite build",
     "type-check": "vue-tsc --build --force"

BIN
public/fonts/SourceHanSansCN-Heavy.otf


BIN
public/images/wsyd/Volume btn_off.png


BIN
public/images/wsyd/Volume btn_on.png


BIN
public/images/wsyd/auto-suspend.png


BIN
public/images/wsyd/auto.png


BIN
public/images/wsyd/dollhouse.png


BIN
public/images/wsyd/enlarge_on.png


BIN
public/images/wsyd/floor.png


BIN
public/images/wsyd/hotlist.png


BIN
public/images/wsyd/inside.png


BIN
public/images/wsyd/like.png


BIN
public/images/wsyd/menu-bg.jpg


BIN
public/images/wsyd/menu-bg2.jpg


BIN
public/images/wsyd/menu-img.png


BIN
public/images/wsyd/narrow_off.png


BIN
public/images/wsyd/pause.png


BIN
public/images/wsyd/play.png


BIN
public/images/wsyd/share.png


BIN
public/images/wsyd/unlike.png


BIN
public/images/wsyd/viewer.png


+ 7 - 0
src/el.scss

@@ -0,0 +1,7 @@
+@forward 'element-plus/theme-chalk/src/common/var.scss' with (
+  $colors: (
+    'primary': (
+      'base': #b21e26,
+    ),
+  )
+);

+ 196 - 0
src/hotspot/views/hotspot/index.wsyd.scss

@@ -0,0 +1,196 @@
+.hotspot-page {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding: 22px 0 71px 30px;
+  z-index: var(--z-index-popper);
+
+  h3 {
+    padding: 22px 10px 10px;
+    font-family: 'Source Han Sans CN-Bold';
+    font-size: 48px;
+    color: #b21e26;
+  }
+  .audioIcon {
+    position: absolute;
+    right: 20px;
+    bottom: 5px;
+
+    img {
+      width: 57px;
+      height: 57px;
+      cursor: pointer;
+    }
+  }
+  &-info {
+    color: #b21e26;
+    max-width: 810px;
+    width: calc(100vw - 30vw);
+    text-align: justify;
+
+    p {
+      text-indent: 2em;
+      font-size: 18px;
+      font-family: 'Source Han Sans CN-Medium';
+    }
+  }
+
+  &-container {
+    position: relative;
+    flex: 1;
+    flex-shrink: 1;
+    height: 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 9vh 20px;
+    max-width: 1320px;
+    min-width: 400px;
+    width: auto;
+    box-sizing: border-box;
+  }
+
+  &-swiper {
+    &__left,
+    &__right {
+      position: absolute;
+      top: 50%;
+      width: 25px;
+      height: 24px;
+      cursor: pointer;
+      transform: translateY(-50%);
+      z-index: 1;
+    }
+    &__left {
+      left: -70px;
+      background: url('@hotspot/assets/images/icon-previous@2x-min.png') no-repeat center / contain;
+    }
+    &__right {
+      right: -70px;
+      background: url('@hotspot/assets/images/icon-next@2x-min.png') no-repeat center / contain;
+    }
+  }
+  &-model {
+    width: 100%;
+    height: 100%;
+
+    iframe {
+      width: 100%;
+      height: 100%;
+    }
+  }
+  .swiper-slide {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+  &-video {
+    height: 100%;
+    max-height: 100%;
+  }
+  &-img {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: inherit;
+
+    &-swiper {
+      flex: 1;
+      width: 100%;
+      height: 0;
+    }
+  }
+
+  &-nav {
+    position: absolute;
+    left: 50%;
+    bottom: 5px;
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    transform: translateX(-50%);
+
+    &__item {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      gap: 9px;
+      width: 57px;
+      height: 57px;
+      box-sizing: border-box;
+      cursor: pointer;
+
+      &.active {
+      }
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+}
+
+@media only screen and (max-width: 600px) {
+  .hotspot-page {
+    padding-left: 0;
+
+    h3 {
+      padding: 30px 10px 10px;
+      font-size: 24px;
+    }
+    .el-scrollbar {
+      width: calc(100% - 60px);
+    }
+    &-info {
+      margin: 0 auto;
+      width: 100%;
+
+      p {
+        font-size: 12px;
+      }
+    }
+    &-container {
+      max-width: 100%;
+      width: 100%;
+      min-width: 100%;
+      background: none;
+    }
+    &-swiper {
+      &__left,
+      &__right {
+        top: unset;
+        bottom: 12px;
+        transform: none;
+      }
+      &__left {
+        left: 14px;
+      }
+      &__right {
+        right: 14px;
+      }
+    }
+    &-nav {
+      bottom: 0;
+
+      &__item {
+        width: 48px;
+        height: 48px;
+      }
+    }
+    .audioIcon {
+      right: 35px;
+      bottom: 1px;
+
+      img {
+        width: 48px;
+        height: 48px;
+      }
+    }
+  }
+}

+ 279 - 0
src/hotspot/views/hotspot/index.wsyd.vue

@@ -0,0 +1,279 @@
+<template>
+  <div class="hotspot-page">
+    <h3>{{ myTitle }}</h3>
+
+    <div class="hotspot-page-container">
+      <!-- 音频播放器 -->
+      <audio
+        id="myAudio"
+        v-if="audio"
+        ref="volumeRef"
+        v-show="isOneAduio"
+        :src="audio"
+        controls
+      ></audio>
+
+      <!-- 模型页面 -->
+      <Swiper
+        v-if="myType === 'model'"
+        class="hotspot-page-swiper hotspot-page-model"
+        @swiper="initSwiper"
+        @slideChange="handleChange"
+      >
+        <SwiperSlide v-for="(item, index) in curList" :key="item.url">
+          <iframe v-if="index === myInd" :src="item" frameborder="0" />
+        </SwiperSlide>
+      </Swiper>
+
+      <!-- 视频页面 -->
+      <div v-if="myType === 'video'" class="hotspot-page-swiper hotspot-page-video">
+        <template v-for="(item, index) in curList" :key="item.url">
+          <video
+            v-if="index === myInd"
+            id="videoID"
+            class="hotspot-page-video"
+            controls
+            :src="item.url"
+            autoplay
+          />
+        </template>
+      </div>
+
+      <!-- 图片页面 -->
+      <Swiper
+        v-if="myType === 'img'"
+        class="hotspot-page-swiper hotspot-page-img-swiper"
+        @swiper="initSwiper"
+        @slideChange="handleChange"
+      >
+        <SwiperSlide v-for="(item, idx) in curList" :key="item">
+          <div class="hotspot-page-img">
+            <el-image
+              :src="item"
+              fit="contain"
+              style="width: 100%; height: 100%"
+              preview-teleported
+              :preview-src-list="curList"
+              :initial-index="idx"
+            />
+          </div>
+        </SwiperSlide>
+      </Swiper>
+
+      <template v-if="curList.length > 1">
+        <div class="hotspot-page-swiper__left" @click="handlePre" />
+        <div class="hotspot-page-swiper__right" @click="handleNext" />
+      </template>
+
+      <!-- 底部的tab -->
+      <div v-if="flooTab.length > 1" class="hotspot-page-nav">
+        <div
+          v-for="item in flooTab"
+          :key="item.id"
+          :class="[
+            'hotspot-page-nav__item',
+            {
+              active: myType === item.type,
+            },
+          ]"
+          @click="handleTab(item)"
+        >
+          <img :class="`${item.type}-icon`" :src="myType === item.type ? item.acIcon : item.icon" />
+          <!-- {{ item.name }}
+          {{ item.type === 'img' ? `${myInd + 1}/${data.img.length}` : '' }} -->
+        </div>
+      </div>
+
+      <!-- 音频图标 -->
+      <div
+        v-if="audio && !isOneAduio"
+        class="audioIcon"
+        :title="audioSta ? '关闭音频' : '打开音频'"
+        @click="audioSta = !audioSta"
+      >
+        <img :src="audioSta ? VolumeOff : VolumeOn" alt="" />
+      </div>
+    </div>
+
+    <el-scrollbar :height="188" style="margin-top: 20px; height: 188px; flex-shrink: 0">
+      <div class="hotspot-page-info">
+        <p>{{ myTxt }}</p>
+      </div>
+    </el-scrollbar>
+  </div>
+</template>
+
+<script>
+  import { Swiper, SwiperSlide } from 'swiper/vue';
+  import 'swiper/css';
+  import { parseUrlParams } from '@/utils';
+
+  import ModelIcon from '@hotspot/assets/images/icon-model@2x.png';
+  import AcModelIcon from '@hotspot/assets/images/icon-model-1@2x.png';
+  import ImageIcon from '@hotspot/assets/images/icon-image@2x.png';
+  import AcImageIcon from '@hotspot/assets/images/icon-image-1@2x.png';
+  import VideoIcon from '@hotspot/assets/images/icon-video@2x.png';
+  import AcVideoIcon from '@hotspot/assets/images/icon-video-1@2x.png';
+  import VolumeOn from '@hotspot/assets/images/Volume-on.png';
+  import VolumeOff from '@hotspot/assets/images/Volume-off.png';
+
+  const urlParams = parseUrlParams(window.location.href);
+
+  export default {
+    name: 'hotspot',
+    components: {
+      Swiper,
+      SwiperSlide,
+    },
+    data() {
+      return {
+        VolumeOn,
+        VolumeOff,
+        m: urlParams.m,
+        id: urlParams.id,
+        // 音频地址
+        audio: '',
+        // 如果只有单独的音频
+        isOneAduio: false,
+        // 音频状态
+        audioSta: false,
+
+        data: {
+          // 模型数组
+          model: [],
+          // 视频数组
+          video: [],
+          // 图片数组
+          img: [],
+        },
+        // 当前 type
+        myType: '',
+
+        // 当前索引
+        myInd: 0,
+
+        // 底部的tab
+        flooTab: [],
+
+        // 标题
+        myTitle: '',
+        // 内容
+        myTxt: '',
+        // 视频内容
+        videoTxt: [],
+        imgTxt: [],
+
+        // 只有标题和文字(没有视频,没有模型,没有图片)
+        oneTxt: false,
+      };
+    },
+    computed: {
+      curList() {
+        return this.data[this.myType] || [];
+      },
+    },
+    watch: {
+      audioSta(val) {
+        if (val) {
+          this.$refs.volumeRef.play();
+          this.$refs.volumeRef.onended = () => {
+            // console.log("----音频播放完毕");
+            this.audioSta = false;
+          };
+        } else this.$refs.volumeRef.pause();
+      },
+    },
+    mounted() {
+      this.getData();
+    },
+    methods: {
+      async getData() {
+        // https://www.4dmodel.com/
+        let url = `https://super.4dage.com/data/${this.id}/hot/js/data.js?time=${Math.random()}`;
+        let result = await fetch(url).then((response) => response.json());
+        const resData = result[this.m];
+        console.log('----', resData);
+        if (resData) {
+          this.audio = resData.backgroundMusic;
+          // 只有单独的音频上传
+          if (resData.backgroundMusic && !resData.model && !resData.video && !resData.images) {
+            this.isOneAduio = true;
+          }
+          // 底部的tab
+          const arr = [];
+          const obj = {};
+          if (resData.model) {
+            obj.model = resData.model;
+            arr.push({ id: 1, type: 'model', name: '模型', icon: ModelIcon, acIcon: AcModelIcon });
+          }
+          if (resData.video) {
+            obj.video = resData.video;
+            arr.push({ id: 2, type: 'video', name: '视频', icon: VideoIcon, acIcon: AcVideoIcon });
+          } else {
+            this.$nextTick(() => {
+              if (
+                !window.navigator.userAgent.match(
+                  /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
+                )
+              ) {
+                this.audioSta = true;
+                this.$refs.volumeRef.play();
+              }
+            });
+          }
+          if (resData.images) {
+            obj.img = resData.images;
+            arr.push({ id: 3, type: 'img', name: '图片', icon: ImageIcon, acIcon: AcImageIcon });
+          }
+          this.flooTab = arr;
+          this.data = obj;
+
+          // 当前type的值 应该为
+          if (resData.model) this.myType = 'model';
+          else if (resData.video) this.myType = 'video';
+          else if (resData.images) this.myType = 'img';
+
+          this.myTitle = resData.title || '';
+          this.myTxt = resData.content || '';
+          this.videoTxt = resData.videosDesc || [];
+          this.imgTxt = resData.imagesDesc || [];
+
+          // 只有 标题和 文字介绍(没有视频,没有模型,没有图片)
+          if (!obj.model && !obj.video && !obj.img && !resData.backgroundMusic) {
+            this.oneTxt = true;
+          }
+        }
+      },
+
+      handleTab(item) {
+        this.myInd = 0;
+        this.myType = item.type;
+      },
+
+      initSwiper(swiper) {
+        this.swiper = swiper;
+      },
+      handleChange({ activeIndex }) {
+        this.myInd = activeIndex;
+      },
+      handlePre() {
+        if (this.myType === 'video') {
+          this.myInd = this.myInd > 0 ? this.myInd - 1 : this.curList.length - 1;
+        } else {
+          this.swiper?.slidePrev();
+        }
+      },
+      handleNext() {
+        if (this.myType === 'video') {
+          this.myInd = this.myInd < this.curList.length - 1 ? this.myInd + 1 : 0;
+        } else {
+          this.swiper?.slideNext();
+        }
+      },
+    },
+  };
+</script>
+
+<style lang="scss">
+  @use './index.wsyd.scss';
+</style>

+ 4 - 0
src/index/app.scss

@@ -83,6 +83,10 @@ iframe {
   src: url('/fonts/SourceHanSansCN-Bold.otf');
 }
 @font-face {
+  font-family: 'Source Han Sans CN-Heavy';
+  src: url('/fonts/SourceHanSansCN-Heavy.otf');
+}
+@font-face {
   font-family: 'Source Han Sans CN-Medium';
   src: url('/fonts/SourceHanSansCN-Medium.otf');
 }

BIN
src/index/assets/images/wsyd/hot-bg-min.jpg


BIN
src/index/assets/images/wsyd/hot-bg.png


BIN
src/index/assets/images/wsyd/mobile/hot-bg.jpg


BIN
src/index/assets/images/wsyd/sidebar-bg-min.png


BIN
src/index/assets/images/wsyd/sidebar-btn.png


BIN
src/index/assets/images/wsyd/sidebar-close-min.png


BIN
src/index/assets/images/wsyd/sidebar-img.png


+ 21 - 0
src/index/router/index.wsyd.ts

@@ -0,0 +1,21 @@
+import { createRouter, createWebHashHistory, type RouteRecordRaw } from 'vue-router';
+
+const routes: Array<RouteRecordRaw> = [
+  {
+    path: '/',
+    name: 'cover',
+    component: () => import('@/views/cover/index.vue'),
+  },
+  {
+    path: '/scene',
+    name: 'home',
+    component: () => import('@/views/home'),
+  },
+];
+
+const router = createRouter({
+  history: createWebHashHistory(import.meta.env.BASE_URL),
+  routes,
+});
+
+export default router;

+ 6 - 0
src/index/utils/index.ts

@@ -19,3 +19,9 @@ export function parseUrlParams(url: string): Record<string, string> {
 
   return params;
 }
+
+export function judgeIsMobile() {
+  return navigator.userAgent.match(
+    /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
+  );
+}

BIN
src/index/views/cover/images/bg.jpg


BIN
src/index/views/cover/images/bg2.png


BIN
src/index/views/cover/images/btn.png


BIN
src/index/views/cover/images/guide.png


BIN
src/index/views/cover/images/mobile/bg.jpg


BIN
src/index/views/cover/images/mobile/bg2.png


BIN
src/index/views/cover/images/title.png


+ 82 - 0
src/index/views/cover/index.scss

@@ -0,0 +1,82 @@
+@use '@/assets/utils.scss';
+
+.cover {
+  position: relative;
+  height: 100vh;
+  overflow: hidden;
+  background: url('./images/bg.jpg') no-repeat center / cover;
+
+  &__img {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: utils.vh-calc(676);
+    height: utils.vh-calc(920);
+  }
+  &__title {
+    position: absolute;
+    top: utils.vh-calc(34);
+    right: utils.vw-calc(75);
+    width: utils.vw-calc(448);
+    height: utils.vw-calc(804);
+  }
+  &__guide {
+    position: absolute;
+    left: utils.vw-calc(609);
+    bottom: utils.vh-calc(83);
+    width: utils.vw-calc(510);
+    height: utils.vw-calc(438);
+    z-index: 1;
+  }
+  &__btn {
+    position: absolute;
+    right: utils.vw-calc(221);
+    bottom: utils.vh-calc(97);
+    width: utils.vw-calc(321);
+    height: utils.vw-calc(71);
+    cursor: pointer;
+    z-index: 2;
+  }
+}
+
+.mb-cover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  overflow: hidden;
+  background: url('./images/mobile/bg.jpg') no-repeat center / cover;
+
+  &__img {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: utils.vh-calc(470);
+    height: utils.vh-calc(882);
+  }
+  &__title {
+    position: absolute;
+    top: utils.vh-calc(163);
+    right: utils.vh-calc(58);
+    width: utils.vh-calc(447);
+    height: utils.vh-calc(805);
+  }
+  &__guide {
+    position: absolute;
+    left: utils.vh-calc(33);
+    bottom: utils.vh-calc(52);
+    width: utils.vh-calc(510);
+    height: utils.vh-calc(438);
+    z-index: 1;
+  }
+  &__btn {
+    position: absolute;
+    left: utils.vh-calc(33);
+    bottom: utils.vh-calc(532);
+    width: utils.vh-calc(321);
+    height: utils.vh-calc(71);
+    cursor: pointer;
+    z-index: 2;
+  }
+}

+ 37 - 0
src/index/views/cover/index.vue

@@ -0,0 +1,37 @@
+<template>
+  <div v-if="!isMobile" class="cover">
+    <img class="cover__img" src="./images/bg2.png" draggable="false" />
+    <img class="cover__title" src="./images/title.png" draggable="false" />
+    <img class="cover__guide" src="./images/guide.png" draggable="false" />
+
+    <img
+      class="cover__btn"
+      src="./images/btn.png"
+      draggable="false"
+      @click="$router.push({ name: 'home' })"
+    />
+  </div>
+
+  <div v-else class="mb-cover">
+    <img class="mb-cover__img" src="./images/mobile/bg2.png" draggable="false" />
+    <img class="mb-cover__title" src="./images/title.png" draggable="false" />
+    <img class="mb-cover__guide" src="./images/guide.png" draggable="false" />
+
+    <img
+      class="mb-cover__btn"
+      src="./images/btn.png"
+      draggable="false"
+      @click="$router.push({ name: 'home' })"
+    />
+  </div>
+</template>
+
+<script setup>
+  import { judgeIsMobile } from '@/utils';
+
+  const isMobile = judgeIsMobile();
+</script>
+
+<style lang="scss" scoped>
+  @use './index.scss';
+</style>

+ 96 - 0
src/index/views/home/components/article-popup/index.scss

@@ -0,0 +1,96 @@
+@use '@/assets/utils.scss';
+
+.article-popup {
+  --el-dialog-box-shadow: none;
+  width: utils.vw-calc(1475);
+  height: utils.vw-calc(565);
+  background: url('@/assets/images/wsyd/sidebar-bg-min.png') no-repeat center / contain;
+
+  &::after {
+    content: '';
+    position: absolute;
+    right: utils.vw-calc(51);
+    bottom: utils.vw-calc(57);
+    width: utils.vw-calc(147);
+    height: utils.vw-calc(267);
+    background: url('@/assets/images/wsyd/sidebar-img.png') no-repeat center / contain;
+  }
+  &__close {
+    position: absolute;
+    top: utils.vw-calc(169);
+    right: utils.vw-calc(-35);
+    width: utils.vw-calc(72);
+    height: utils.vw-calc(72);
+    cursor: pointer;
+    z-index: 1;
+  }
+  &-tabs {
+    position: absolute;
+    top: utils.vw-calc(125);
+    left: utils.vw-calc(220);
+    display: flex;
+    flex-wrap: nowrap;
+    font-size: utils.vw-calc(24);
+    line-height: utils.vw-calc(24);
+
+    li {
+      position: relative;
+      margin: 0 utils.vw-calc(60);
+      font-family: 'Source Han Sans CN-Bold';
+      color: #d8171e;
+      text-shadow: 4px 0px 4px rgba(104, 58, 13, 0.08);
+      cursor: pointer;
+
+      &:hover,
+      &.active {
+        color: #ffd800;
+      }
+      &:first-child {
+        margin-left: 0;
+
+        &::before {
+          display: none;
+        }
+      }
+      &::before {
+        content: '';
+        position: absolute;
+        top: 50%;
+        left: utils.vw-calc(-55);
+        width: utils.vw-calc(1);
+        height: utils.vw-calc(20);
+        background: #d8171e;
+        transform: translateY(-50%);
+      }
+    }
+  }
+
+  h3 {
+    position: absolute;
+    top: utils.vw-calc(210);
+    left: 50%;
+    color: #b21e26;
+    letter-spacing: 2px;
+    font-size: utils.vw-calc(48);
+    font-family: 'Source Han Sans CN-Bold';
+    transform: translateX(-50%);
+  }
+
+  &-content {
+    position: absolute;
+    top: utils.vw-calc(292);
+    left: utils.vw-calc(284);
+    padding-right: 20px;
+    width: utils.vw-calc(936);
+    height: utils.vw-calc(188);
+    color: #b21e26;
+    text-align: justify;
+
+    p {
+      margin-bottom: utils.vw-calc(20);
+      text-indent: 2em;
+      font-size: utils.vw-calc(18);
+      line-height: utils.vw-calc(35);
+    }
+  }
+}

+ 89 - 0
src/index/views/home/components/article-popup/index.vue

@@ -0,0 +1,89 @@
+<template>
+  <el-dialog
+    class="article-popup"
+    v-model="show"
+    :close-on-click-modal="false"
+    :show-close="false"
+    :modal="false"
+  >
+    <img
+      class="article-popup__close"
+      src="@/assets/images/wsyd/sidebar-close-min.png"
+      @click="show = false"
+    />
+
+    <ul class="article-popup-tabs">
+      <li
+        v-for="(item, index) in LIST"
+        :key="item.title"
+        :class="{ active: activeTab === index }"
+        @click="activeTab = index"
+      >
+        <span>{{ item.title }}</span>
+      </li>
+    </ul>
+
+    <h3>{{ currentItem.title }}</h3>
+    <el-scrollbar srcoll-y class="article-popup-content">
+      <div v-html="currentItem.content" />
+    </el-scrollbar>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+  import { computed, ref } from 'vue';
+
+  const LIST = [
+    {
+      title: '前言',
+      content: `
+      <p>1925年爆发的震惊中外的五卅运动,标志着大革命高潮的到来。</p>
+      <p>中国共产党领导的五卅运动,是中华民族直接反抗帝国主义的伟大运动。它冲破了长期笼罩全国的沉闷的政治空气,大大促进了群众的觉醒,显示了各革命阶级、各阶层民众在无产阶级领导下联合斗争的巨大威力,给帝国主义和军阀势力一次前所未有的打击,有力地推动了国民革命运动的蓬勃发展,彰显了伟大建党精神的实践价值。</p>
+      <p>为纪念五卅运动100周年,中共一大纪念馆特举办此展,以缅怀革命先辈的英勇事迹,弘扬伟大建党精神,激励广大党员干部群众在中国式现代化的道路上砥砺前行,为全面推进强国建设、民族复兴伟业不懈奋斗!</p>
+      `,
+    },
+    {
+      title: '新生·锋芒',
+      content: `<p>近代中国成为半殖民地半封建国家,国家蒙辱、人民蒙难、文明蒙尘。中国共产党在上海诞生后,高度重视工人运动,通过组织工会、领导罢工提升工人阶级觉悟,推动工人运动发展,为后续革命积累了宝贵经验、奠定了重要基础。</p>`,
+    },
+    {
+      title: '前哨·斗争',
+      content: `<p>1925年2月2日,日商内外棉第八厂殴打开除中国工人。在中国共产党领导下,大规模总同盟罢工爆发。党组织在领导二月罢工中积累宝贵经验,堪称五卅运动的前哨战。5月15日,内外棉第七厂日本资本家枪杀工人党员顾正红,激起民债,成为五卅运动的导火索。</p>`,
+    },
+    {
+      title: '热血·迸发',
+      content: `<p>五卅惨案激发了全上海乃至全中国人民的极大愤怒,在中国共产党的领导和推动下,反帝爱国怒潮从工人发展到学生、商人等社会各阶层,形成工人罢工、学生罢课、商人罢市的局面。</p>`,
+    },
+    {
+      title: '怒嘲·燎原',
+      content: `<p>在中国共产党鼓舞下,一场反帝爱国运动在全国范围轰轰烈烈地开展起来。这一运动波及27个省区,有将近700个市、县、城镇投入,参加运动的各方面人士约1700万人。</p>`,
+    },
+    {
+      title: '结语',
+      content: `
+      <p>百年前的1925年,五卅运动如一声惊雷,划破黑暗的长空,震撼了整个中国大地。在那风云激荡的岁月里,无数英勇先驱挺身而出,以热血和生命谱写了一曲壮丽的抗争之歌。</p>
+      <p>如今,悠悠百年已逝,曾经帝国主义肆意剥削和残酷压迫中国人民的屈辱时代早已一去不复返。而中国人民在五卅运动中所彰显的不畏强暴、不怕晒牲的崇高精神,仍熠熠生辉。让我们在新时代的征程中,坚定理想信念,勇担时代使命,继续挥洒我们的热血,绘就属于我们的热血篇章!</p>
+      `,
+    },
+  ];
+
+  const props = defineProps<{
+    visible: boolean;
+  }>();
+  const emits = defineEmits(['update:visible']);
+
+  const show = computed({
+    get() {
+      return props.visible;
+    },
+    set(v) {
+      emits('update:visible', v);
+    },
+  });
+  const activeTab = ref(0);
+  const currentItem = computed(() => LIST[activeTab.value]);
+</script>
+
+<style lang="scss">
+  @use './index.scss';
+</style>

+ 2 - 2
src/index/views/home/components/guide/index.scss

@@ -135,7 +135,7 @@
 .frame .slidee li.thumbImg.active > img,
 .frame .slidee li.thumbImg.hasHover.active > img:hover {
   opacity: 1;
-  border-color: #00b4ed;
+  border-color: var(--el-color-primary);
 }
 
 .scrollbar {
@@ -202,7 +202,7 @@
       background-color: #575757;
     }
     &.active::before {
-      background-color: #00b4ed;
+      background-color: var(--el-color-primary);
     }
   }
 }

+ 150 - 0
src/index/views/home/components/hot-spot-list/index.wsyd.scss

@@ -0,0 +1,150 @@
+#hotListWrap {
+  display: flex;
+  flex-direction: column;
+  position: absolute;
+  top: 0;
+  right: -400px;
+  width: 408px !important;
+  height: 100%;
+  color: #ae1617;
+  background: url('@/assets/images/wsyd/hot-bg-min.jpg') no-repeat center / cover;
+  transition: right 0.4s, width 0.5s;
+  z-index: var(--z-index-popper);
+}
+
+.hotListActive {
+  right: 0 !important;
+}
+
+#hotListTitle {
+  position: relative;
+  padding: 69px 0 16px;
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  text-align: center;
+  font-family: 'Source Han Sans CN-Heavy';
+}
+
+#hotListContent {
+  width: 100%;
+  flex-grow: 1;
+  height: 100%;
+  overflow-y: scroll;
+  overflow-x: hidden;
+}
+
+#hotListBottom {
+  margin: 30px 0;
+  text-align: center;
+}
+
+#hotListClose {
+  width: 72px;
+  height: 72px;
+  cursor: pointer;
+}
+
+#hotListContent ul {
+  font-size: 20px;
+  font-family: 'Source Han Sans CN-Regular';
+}
+
+#hotListContent ul li {
+  height: 68px;
+  line-height: 68px;
+  text-align: center;
+  padding: 0 25px;
+  transition: color 0.3s, background 0.6s;
+  border-radius: 10px;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  cursor: pointer;
+}
+
+#hotListContent ul li:hover {
+  color: #ffd800;
+}
+
+#hotListContent ul li.active {
+  color: #ffd800;
+}
+
+#hotListText {
+  font-size: 30px;
+  letter-spacing: 4px;
+}
+
+#hotListIcon {
+  width: 34px;
+  margin-left: 48px;
+}
+
+#hotListContent::-webkit-scrollbar {
+  width: 6px;
+}
+
+#hotListContent::-webkit-scrollbar-thumb {
+  border-radius: 10px;
+  background-color: #979cab;
+}
+
+#hotListContent::-webkit-scrollbar-track {
+  border-radius: 10px;
+}
+
+@media only screen and (max-width: 910px) {
+  #hotListWrap {
+    top: -120vh;
+    left: 18px;
+    right: 18px !important;
+    width: unset !important;
+    height: calc(100vh - 36px);
+    transition: top 0.4s, width 0.5s;
+  }
+  .hotListActive {
+    top: 18px !important;
+  }
+
+  #hotListTitle {
+    padding: 60px 0 10px;
+  }
+  #hotListContent {
+    /* background: rgba(34, 36, 37,0.9); */
+    background: none;
+  }
+  #hotListText {
+    font-size: 24px;
+    letter-spacing: 3px;
+  }
+  #hotListIcon {
+    width: 24px;
+    margin-left: 26px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(165%, -50%);
+  }
+  #hotListContent ul li {
+    text-align: center;
+    height: 40px;
+    line-height: 40px;
+  }
+  #hotListContent ul {
+    padding: 0 30px;
+    font-size: 16px;
+  }
+  #hotListBottom {
+    margin: 30px 0;
+  }
+  #hotListClose {
+    width: 33px;
+    height: 33px;
+  }
+  #hotListContent ul li.active {
+    color: white;
+    background: none;
+  }
+}

+ 24 - 0
src/index/views/home/components/hot-spot-list/index.wsyd.tsx

@@ -0,0 +1,24 @@
+import { defineComponent } from 'vue';
+import CloseIcon from '@/assets/images/wsyd/sidebar-close-min.png';
+import './index.wsyd.scss';
+
+export default defineComponent({
+  name: 'HomeHotSpotList',
+  render() {
+    return (
+      <div id="hotListWrap">
+        <div id="hotListTitle">
+          <div>
+            <span id="hotListText">热点列表</span>
+          </div>
+        </div>
+        <div id="hotListContent">
+          <ul></ul>
+        </div>
+        <div id="hotListBottom">
+          <img id="hotListClose" src={CloseIcon} alt="" />
+        </div>
+      </div>
+    );
+  },
+});

+ 193 - 0
src/index/views/home/components/menu/index.wsyd.scss

@@ -0,0 +1,193 @@
+.pinBottom-container {
+  position: absolute;
+  left: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  bottom: 24px;
+  width: 1224px;
+  height: 69px;
+  transition: all 0.5s;
+  transform: translate(-50%);
+  background: url('/images/wsyd/menu-bg.jpg') no-repeat center / 100% 100%;
+  z-index: var(--z-index-top);
+
+  &.playing {
+    bottom: 44px;
+  }
+  &.open {
+    bottom: 139px;
+
+    &.playing {
+      bottom: 157px;
+    }
+  }
+  .pinBottom {
+    display: flex;
+    align-items: center;
+    gap: 34px;
+
+    &.right {
+      gap: 46px;
+    }
+    > div,
+    > div > a {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      font-size: 14px;
+      line-height: 14px;
+      color: #ffdf9e;
+      cursor: pointer;
+
+      &:hover,
+      &.active,
+      &.opened {
+        color: #ffd800;
+      }
+      img,
+      .icon {
+        width: 34px;
+        height: 34px;
+      }
+      p {
+        margin-top: 5px;
+      }
+    }
+  }
+}
+
+#pullTab {
+  .icon {
+    background: url('/images/wsyd/auto.png') no-repeat center / contain;
+  }
+  &.opened .icon {
+    background-image: url('/images/wsyd/auto-suspend.png');
+  }
+}
+
+.terms2,
+#vr {
+  display: none !important;
+}
+
+.icon-fullscreen {
+  background: url('/images/wsyd/enlarge_on.png') no-repeat center / contain;
+}
+.icon-fullscreen-exit {
+  background: url('/images/wsyd/narrow_off.png') no-repeat center / contain;
+}
+
+.pinBottom-border {
+  position: relative;
+  top: -22px;
+  margin: 0 36px;
+  width: 96px;
+  height: 134px;
+}
+
+.icon-share {
+  background: url('/images/wsyd/share.png') no-repeat center / contain;
+}
+
+.icon-viewer {
+  background: url('/images/wsyd/viewer.png') no-repeat center / contain;
+}
+
+#thumb {
+  .icon-slot {
+    transition: background ease-in 0.2s;
+    background: url('/images/wsyd/unlike.png') no-repeat center / contain;
+  }
+
+  &.active .icon-slot {
+    background-image: url('/images/wsyd/like.png');
+  }
+}
+
+@media only screen and (max-width: 600px) {
+  .pinBottom-container {
+    bottom: 0;
+    width: 100%;
+    height: unset;
+    background: none;
+
+    &.playing {
+      bottom: 27px;
+    }
+    &.open {
+      bottom: 95px;
+
+      &.playing {
+        bottom: 115px;
+      }
+    }
+    .pinBottom {
+      gap: 15px;
+
+      &.left {
+        position: absolute;
+        left: 10px;
+        bottom: 7px;
+        margin: 0;
+        padding: 20px 0 27px;
+        flex-direction: column;
+        justify-content: center;
+        width: 50px;
+        background: url('/images/wsyd/menu-bg2.jpg') no-repeat center top / cover;
+
+        &::before {
+          content: '';
+          position: absolute;
+          top: -50px;
+          left: 4px;
+          width: 45px;
+          height: 67px;
+          background: url('/images/wsyd/menu-img.png') no-repeat center / contain;
+          z-index: 1;
+        }
+      }
+      &.right {
+        padding: 20px 0 27px;
+        gap: 30px;
+        position: absolute;
+        right: 10px;
+        bottom: 7px;
+        flex-direction: column;
+        justify-content: center;
+        width: 50px;
+        background: url('/images/wsyd/menu-bg2.jpg') no-repeat center top / cover;
+      }
+      > div,
+      > div > a {
+        font-size: 10px;
+
+        img,
+        .icon {
+          width: 17px;
+          height: 17px;
+        }
+        p {
+          margin-top: 4px;
+          letter-spacing: 1px;
+        }
+      }
+    }
+    .pinBottom-border {
+      display: none;
+    }
+  }
+}
+
+@media only screen and (max-width: 487px), (max-height: 487px) {
+  .pinBottom-container.drawerOpen.duringTour {
+    bottom: 6px;
+  }
+  #gui .pinBottom.open.noScroll {
+    bottom: 93px;
+  }
+  .pinBottom.open.noScroll.playing {
+    bottom: 108px;
+  }
+}

+ 151 - 0
src/index/views/home/components/menu/index.wsyd.vue

@@ -0,0 +1,151 @@
+<template>
+  <div class="pinBottom-container">
+    <div class="pinBottom left">
+      <div id="previous" class="previous desktop-only ui-icon" style="display: none">
+        <a>
+          <img src="/images/wsyd/play.png" width="24" height="24" data-original-title="播放" />
+        </a>
+      </div>
+      <div id="play" class="ui-icon" data-original-title="自动漫游">
+        <a>
+          <img src="/images/wsyd/play.png" width="24" height="24" />
+          <p>自动漫游</p>
+        </a>
+      </div>
+      <div id="pause" class="ui-icon" style="display: none">
+        <a>
+          <img title="暂停" src="/images/wsyd/pause.png" width="24" height="24" />
+          <p>自动漫游</p>
+        </a>
+      </div>
+      <div id="next" class="next desktop-only ui-icon wide" style="display: none">
+        <a>
+          <i title="" class="icon icon-dpad-right" data-original-title="下一个"></i>
+        </a>
+      </div>
+      <div data-original-title="导览" id="pullTab" title="">
+        <i class="icon icon-inside" title="场景导览" />
+        <p>场景导览</p>
+      </div>
+      <div data-original-title="热点列表" id="hotList" title="" style="display: none">
+        <img class="icon icon-inside" src="/images/wsyd/hotlist.png" title="热点列表" />
+        <p>热点列表</p>
+      </div>
+      <div data-original-title="全景漫游" id="gui-modes-inside" title="" class="hidden">
+        <img class="icon icon-inside" src="/images/wsyd/inside.png" title="全景漫游" />
+        <p>全景漫游</p>
+      </div>
+      <div data-original-title="迷你模型" id="gui-modes-dollhouse" title="" class="">
+        <img class="icon icon-inside" src="/images/wsyd/dollhouse.png" title="迷你模型" />
+        <p>迷你模型</p>
+      </div>
+      <div data-original-title="俯视图" id="gui-modes-floorplan" title="">
+        <img class="icon icon-inside" src="/images/wsyd/floor.png" title="俯视图" />
+        <p>俯视图</p>
+      </div>
+      <div
+        data-original-title="消除外壳"
+        id="gui-remove-face"
+        title=""
+        style="display: none; float: left"
+      >
+        <img class="icon icon-inside" src="/images/face.jpg" />
+      </div>
+    </div>
+
+    <img class="pinBottom-border" src="/images/wsyd/menu-img.png" />
+
+    <div class="pinBottom right hideTarget">
+      <div id="thumb" class="ui-icon wide" :class="{ active: animationThumb }" @click="handleThumb">
+        <a>
+          <div class="icon icon-slot" />
+          <p>{{ thumbNum }}</p>
+        </a>
+      </div>
+      <div id="sharing" class="ui-icon wide" title="分享" @click="shareVisible = true">
+        <a>
+          <i class="icon icon-share" />
+          <p>分享</p>
+        </a>
+      </div>
+      <div id="volume" class="ui-icon wide" style="display: none">
+        <a>
+          <img
+            class="icon icon-inside"
+            src="/images/wsyd/Volume btn_on.png"
+            data-default-url="/images/wsyd/Volume btn_on.png"
+            data-active-url="/images/wsyd/Volume btn_off.png"
+          />
+          <p>音乐</p>
+        </a>
+      </div>
+      <el-popover placement="top" :content="`${visitCount}`" effect="dark" trigger="click">
+        <template #reference>
+          <div id="viewer" class="ui-icon wide" title="浏览量">
+            <a>
+              <i class="icon icon-viewer" />
+              <p>浏览量</p>
+            </a>
+          </div>
+        </template>
+      </el-popover>
+      <div id="vr" class="ui-icon wide hidden">
+        <a>
+          <i title="{[{ VIEW_IN_VR }]}" class="icon icon-webvr"></i>
+        </a>
+      </div>
+      <div
+        id="gui-fullscreen"
+        class="ui-icon wide"
+        data-placement="top"
+        title="{[{ VIEW_FULLSCREEN }]}"
+      >
+        <a>
+          <i class="icon icon-fullscreen"></i>
+          <p>全屏</p>
+        </a>
+      </div>
+      <div
+        id="gui-fullscreen-exit"
+        class="ui-icon wide"
+        data-placement="top"
+        title="{[{ EXIT_FULLSCREEN }]}"
+        style="display: none"
+      >
+        <a>
+          <i class="icon icon-fullscreen-exit"></i>
+          <p>全屏</p>
+        </a>
+      </div>
+    </div>
+  </div>
+
+  <share-popup v-model:visible="shareVisible" />
+</template>
+
+<script setup lang="ts">
+  import { ref } from 'vue';
+  import SharePopup from '../share-popup/index.vue';
+
+  const THUMB_KEY = 'thumbs';
+  const shareVisible = ref(false);
+  const thumbNum = ref(Number(localStorage.getItem(THUMB_KEY) ?? 0));
+  const animationThumb = ref(false);
+  const visitCount = localStorage.getItem('visitCount') ?? 0;
+
+  const handleThumb = () => {
+    if (animationThumb.value) return;
+
+    animationThumb.value = true;
+    thumbNum.value += 1;
+    localStorage.setItem(THUMB_KEY, `${thumbNum.value}`);
+
+    setTimeout(() => {
+      animationThumb.value = false;
+    }, 200);
+  };
+</script>
+
+<style lang="scss" scoped>
+  @use './index.wsyd.scss';
+</style>

+ 60 - 0
src/index/views/home/components/popup/index.wsyd.scss

@@ -0,0 +1,60 @@
+#popup {
+  display: none;
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: var(--z-hot-popper);
+
+  .popup-wrap {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    width: 1098px;
+    height: 819px;
+    text-align: center;
+    transform: translate(-50%, -50%);
+    background: url('@/assets/images/wsyd/hot-bg.png') no-repeat center / contain;
+  }
+  &.wait {
+    opacity: 0.1;
+  }
+}
+#id1 {
+  width: 100%;
+  height: 100%;
+}
+.popup-content {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+#closepop {
+  position: absolute;
+  top: 17px;
+  right: 22px;
+  width: 72px;
+  height: 72px;
+  cursor: pointer;
+  text-indent: -999em;
+  background: url('@/assets/images/wsyd/sidebar-close-min.png') no-repeat center / contain;
+}
+
+@media only screen and (max-width: 600px) {
+  #popup {
+    background: rgba($color: #000000, $alpha: 0.7);
+    .popup-wrap {
+      width: calc(100vw - 40px);
+      height: calc(100vh - 100px);
+      background: url('@/assets/images/wsyd/mobile/hot-bg.jpg') no-repeat top left / cover;
+    }
+  }
+  #closepop {
+    top: -18px;
+    right: -13px;
+    width: 35px;
+    height: 35px;
+  }
+}

+ 16 - 0
src/index/views/home/components/popup/index.wsyd.tsx

@@ -0,0 +1,16 @@
+import { defineComponent } from 'vue';
+import './index.wsyd.scss';
+
+export default defineComponent({
+  name: 'HomePopup',
+  render() {
+    return (
+      <div id="popup">
+        <div class="popup-wrap">
+          <div class="popup-content"></div>
+          <div id="closepop">close</div>
+        </div>
+      </div>
+    );
+  },
+});

+ 135 - 0
src/index/views/home/index.wsyd.tsx

@@ -0,0 +1,135 @@
+import { defineComponent, ref } from 'vue';
+import JsScript from '@/components/js-script';
+import ArticlePopup from './components/article-popup/index.vue';
+import Title from './components/title';
+import WebVr from './components/web-vr';
+import Other from './components/other';
+import Guide from './components/guide';
+import Vrcon from './components/vrcon';
+import Menu from './components/menu';
+import GuiLoading from './components/gui-loading';
+import Popup from './components/popup';
+import HotSpotList from './components/hot-spot-list';
+import SidebarIcon from '@/assets/images/wsyd/sidebar-btn.png';
+import { judgeIsMobile } from '@/utils';
+import './index.scss';
+
+// 自定义热点图标
+// @ts-ignore
+// window.hoticon = {
+//   default: '/images/point.png',
+//   higt: '/images/point2.png',
+// };
+
+export default defineComponent({
+  name: 'home',
+  components: {
+    Title,
+    WebVr,
+    Other,
+    Vrcon,
+    GuiLoading,
+    JsScript,
+    Popup,
+  },
+  setup() {
+    const manageJsLoaded = ref(false);
+    const hotJsLoaded = ref(false);
+    const articleVisible = ref(false);
+    const isMobile = judgeIsMobile();
+
+    return {
+      manageJsLoaded,
+      hotJsLoaded,
+      articleVisible,
+      isMobile,
+    };
+  },
+  render() {
+    return (
+      <div class="home">
+        {/* 结语 */}
+        {!this.isMobile && (
+          <>
+            <img
+              src={SidebarIcon}
+              style={{
+                position: 'fixed',
+                top: '78px',
+                right: 0,
+                width: '89px',
+                height: '162px',
+                cursor: 'pointer',
+                zIndex: 1,
+              }}
+              onClick={() => (this.articleVisible = true)}
+            />
+            <ArticlePopup
+              visible={this.articleVisible}
+              onUpdate:visible={(v) => (this.articleVisible = v)}
+            />
+          </>
+        )}
+
+        {/* 进度条加载 */}
+        <GuiLoading />
+
+        {/* 加载初始页面 */}
+        <div id="gui-thumb" />
+
+        {/* 热点弹出框 */}
+        <Popup />
+
+        {/* 场景canvs主容器 */}
+        <div id="player" />
+
+        {/* 底部菜单 */}
+        <div id="gui-parent">
+          {/* 热点气泡 */}
+          <div id="hot" />
+
+          <div id="gui" style="display: none;">
+            {/* 标题 */}
+            <Title />
+
+            {/* 热点列表 */}
+            <HotSpotList />
+
+            {/* 底部菜单 */}
+            <Menu />
+
+            {/* 导览 */}
+            <Guide />
+
+            {/* <div class="home_logo">
+              <img src="images/btm_logo.png" />
+              <span>提供技术支持</span>
+            </div> */}
+          </div>
+
+          <WebVr />
+          <Vrcon />
+          <Other />
+        </div>
+
+        {/* TODO: 没有控制权,耦合严重;放在此处为了防止元素未渲染导致报错 */}
+        <JsScript src="./js/manage.js" onLoad={() => (this.manageJsLoaded = true)} />
+        {this.manageJsLoaded && (
+          <div>
+            <JsScript src="./js/Hot.js" onLoad={() => (this.hotJsLoaded = true)} />
+            {this.hotJsLoaded && (
+              <div>
+                <JsScript src="./js/main_2020_show.js" />
+                {/* 延迟加载 */}
+                <JsScript src="./js/lib/player-0.0.12.min.js" />
+                <JsScript src="./js/lib/Tween.js" />
+                <JsScript src="./js/SpecialScene.js" />
+                <JsScript src="./js/loadCAD.js" />
+              </div>
+            )}
+          </div>
+        )}
+      </div>
+    );
+  },
+});

+ 11 - 2
vite.config.ts

@@ -33,10 +33,18 @@ export default defineConfig(() => {
       vue(),
       vueJsx(),
       AutoImport({
-        resolvers: [ElementPlusResolver()],
+        resolvers: [
+          ElementPlusResolver({
+            importStyle: 'sass',
+          }),
+        ],
       }),
       Components({
-        resolvers: [ElementPlusResolver()],
+        resolvers: [
+          ElementPlusResolver({
+            importStyle: 'sass',
+          }),
+        ],
       }),
     ],
     resolve: {
@@ -89,6 +97,7 @@ export default defineConfig(() => {
       preprocessorOptions: {
         scss: {
           api: 'modern-compiler',
+          additionalData: `@use "/src/el.scss" as *;`,
         },
       },
     },