任一存 преди 2 години
родител
ревизия
5a20d06a70

+ 2 - 1
README.md

@@ -1,2 +1,3 @@
 # 测试环境部署地址
-阿里云-4dkk-culture/华南1(深圳)/wenlange/hotspot/
+阿里云-4dkk-culture/华南1(深圳)/wenlange/hotspot/
+

+ 0 - 1
package.json

@@ -11,7 +11,6 @@
   "dependencies": {
     "axios": "^1.1.3",
     "core-js": "^3.8.3",
-    "d3": "^7.8.0",
     "element-ui": "^2.15.6",
     "html2canvas": "^1.3.3",
     "install": "^0.13.0",

+ 17 - 1
src/App.vue

@@ -1,5 +1,10 @@
 <template>
-  <div id="app">
+  <div
+    id="app"
+    :class="{
+      mobile: isMobile,
+    }"
+  >
     <router-view />
   </div>
 </template>
@@ -20,6 +25,17 @@ body {
   // 有必要给resizer设置border_radius吗?
 	::-webkit-scrollbar-resizer { background: transparent; }
 }
+
+.mobile {
+  ::-webkit-scrollbar { width: 2px; height: 2px; } /*宽度是对垂直滚动条而言,高度是对水平滚动条而言*/
+  ::-webkit-scrollbar-thumb { background: rgba(143, 72, 49, 0.5); border-radius: 1px;}
+  ::-webkit-scrollbar-track { background: transparent; border-radius: 1px;}
+  // 横竖滚动条轨道交汇处
+  ::-webkit-scrollbar-corner { background: transparent; }
+  // 有必要给resizer设置border_radius吗?
+  ::-webkit-scrollbar-resizer { background: transparent; }
+}
+
 *{
   margin: 0;
   padding: 0;

BIN
src/assets/images/option-correct-bg-mobile.png


BIN
src/assets/images/option-wrong-bg-mobile.png


BIN
src/assets/images/share-bg-mobile.png


BIN
src/assets/images/title-decorator-mobile.png


+ 1 - 0
src/main.js

@@ -5,6 +5,7 @@ import App from './App.vue'
 import router from './router'
 import store from './store'
 import axios from 'axios'
+import '@/mixins'
 import 'viewerjs/dist/viewer.css'
 import Viewer from 'v-viewer'
 import VueLazyLoad from 'vue-lazyload'

+ 15 - 0
src/mixins/index.js

@@ -0,0 +1,15 @@
+import Vue from 'vue'
+import browser from '@/utils/browser'
+
+Vue.prototype.$bus = new Vue()
+
+Vue.mixin({
+  data() {
+    return {
+      isMobile: browser.mobile
+    }
+  },
+  methods: {
+  }
+})
+

+ 11 - 16
src/router/index.js

@@ -1,34 +1,29 @@
 import Vue from 'vue'
 import VueRouter from 'vue-router'
-import HomeWeb from '../views/HomeWeb.vue'
-import HomeMobile from '../views/HomeMobile.vue'
+import HomeView from '../views/HomeView.vue'
 import QuestionView from '../views/QuestionView.vue'
+import QuestionViewMobile from '../views/QuestionViewMobile.vue'
 
 Vue.use(VueRouter)
 
 const routes = [
-  // {
-  //   path: '/',
-  //   name: 'Home',
-  //   component: Home
-  // },
   {
-    path: '/web',
-    name: 'HomeWeb',
-    component: HomeWeb,
+    path: '/',
+    name: 'HomeView',
+    component: HomeView,
     children: [
       {
         path: '/question-view',
         name: 'QuestionView',
         component: QuestionView,
-      }
+      },
+      {
+        path: '/question-view-mobile',
+        name: 'QuestionViewMobile',
+        component: QuestionViewMobile,
+      },
     ]
   },
-  {
-    path: '/mobile',
-    name: 'HomeMobile',
-    component: HomeMobile
-  },
 ]
 
 const router = new VueRouter({

+ 0 - 642
src/views/Home.vue

@@ -1,642 +0,0 @@
-<template>
-  <!-- @click="autoplay" @touchstart="autoplay" -->
-  <div class="home">
-    <audio
-      v-if="audio"
-      id="audio1"
-      ref="musicBg"
-      class="audio"
-      :src="audio"
-      preload
-      @ended="overAudio"
-    />
-    <div
-      v-if="(!audio && fixIcon.length > 0) || (audio && fixIcon.length > 1)"
-      class="content"
-      :class="{ isMobileCon: isMobile }"
-    >
-      <div
-        v-if="!isMobile && lengthShow"
-        class="swiper-button-prev"
-        @click="slideto('slidePrev')"
-      />
-      <div
-        v-show="active === 'title' && isMobile"
-        class="mb-intro"
-      >
-        <p v-html="data.title" />
-        <p v-html="data.content" />
-        <p
-          v-if="
-            data.imagesDesc && data.imagesDesc[myInd] && active === 'images'
-          "
-          v-html="data.imagesDesc[myInd]"
-        />
-        <p
-          v-if="data.videosDesc && data.videosDesc[myInd] && active === 'video'"
-          v-html="data.videosDesc[myInd]"
-        />
-      </div>
-      <!-- 查看图片 -->
-      <viewer
-        ref="viewer"
-        class="viewerCla"
-        :images="lookPics"
-      >
-        <img
-          :src="lookPics[0]"
-          alt=""
-        >
-      </viewer>
-
-      <swiper
-        v-show="active !== 'title'"
-        ref="mySwiper"
-        class="warpper"
-        :options="swiperOptions"
-      >
-        <swiper-slide
-          v-for="(item, i) in data[active]"
-          :key="i"
-        >
-          <div class="slide">
-            <img
-              v-if="active === 'images'"
-              v-lazy="fixUrl(item)"
-              style="cursor: pointer"
-              alt=""
-              @click="lookImg(fixUrl(item))"
-            >
-            <video
-              v-else-if="active === 'video'"
-              class="videoDom"
-              :src="fixUrl(item.url)"
-              controls
-            />
-            <iframe
-              v-else-if="active === 'model' || active === 'iframe'"
-              :src="fixUrl(item)"
-              frameborder="0"
-              @click="colseParent(item)"
-            />
-          </div>
-        </swiper-slide>
-        <div
-          v-show="lengthShow"
-          slot="pagination"
-          class="swiper-pagination"
-        />
-      </swiper>
-      <div
-        v-if="!isMobile && lengthShow"
-        class="swiper-button-next"
-        @click="slideto('slideNext')"
-      />
-    </div>
-    <ul
-      v-if="fixIcon.length > 0"
-      class="iconarr"
-      :class="{ oneChuMusic: fixIcon.length === 1 && !audio }"
-    >
-      <li
-        v-for="(item, i) in fixIcon"
-        :key="i"
-        :class="{
-          active: item.id === active || item.audioAc,
-          onlyTxt: audio && fixIcon.length === 2 && i !== 0,
-        }"
-        @click="changeActive(item.id, item.audioAc)"
-      >
-        <img
-          :src="require(`@/assets/images/${item.img}.png`)"
-          alt=""
-        >
-        <span>{{ item.name }}</span>
-      </li>
-    </ul>
-    <!-- 文字解说 -->
-    <div
-      v-if="!isMobile || (isMobile && fixIcon.length <= 0)"
-      class="intro"
-      :class="{
-        ismtop:
-          (!audio && fixIcon.length === 0) || (audio && fixIcon.length === 1),
-      }"
-    >
-      <h3 v-html="data.title" />
-      <p v-html="data.content" />
-      <p
-        v-if="data.imagesDesc && data.imagesDesc[myInd] && active === 'images'"
-        v-html="data.imagesDesc[myInd]"
-      />
-      <p
-        v-if="data.videosDesc && data.videosDesc[myInd] && active === 'video'"
-        v-html="data.videosDesc[myInd]"
-      />
-    </div>
-  </div>
-</template>
-
-<script>
-import { Swiper, SwiperSlide } from "vue-awesome-swiper"
-import "swiper/css/swiper.css"
-import browser from "@/utils/browser"
-
-let iconArr = [
-  {
-    name: "音频",
-    id: "audio",
-    img: "audio-icon",
-    display: false,
-    audioAc: false,
-  },
-  { name: "图片", id: "images", img: "img-icon", display: false },
-  { name: "视频", id: "video", img: "video-icon", display: false },
-  { name: "网页", id: "iframe", img: "iframe-icon", display: false },
-  { name: "模型", id: "model", img: "model-icon", display: false },
-]
-
-browser.mobile &&
-  iconArr.push({ name: "介绍", id: "title", img: "txt-icon", display: false })
-
-export default {
-  name: "Home",
-  components: {
-    Swiper,
-    SwiperSlide,
-  },
-  data() {
-    return {
-      lookPics: [],
-
-      // 图片描述的索引
-      myInd: 0,
-      lengthShow: false,
-      //  看看是不是只有一张图,一个视频或irm,只有一张图的时候隐藏左右按钮和小圆点
-      audio: "",
-      m: this.$route.query.m,
-      id: this.$route.query.id,
-      isMobile: browser.mobile,
-      isAndriod: browser.android,
-      swiperOptions: browser.mobile
-        ? {
-          pagination: {
-            el: ".swiper-pagination",
-            clickable: true,
-          },
-          on: {
-            slideChangeTransitionEnd: () => {
-              let swiper = this.$refs.mySwiper.$swiper
-              let activeIndex = swiper.activeIndex
-              this.myInd = activeIndex
-            },
-          },
-        }
-        : {
-          slidesPerView: 3,
-          spaceBetween: 0,
-          centeredSlides: true,
-          pagination: {
-            el: ".swiper-pagination",
-            clickable: true,
-          },
-          on: {
-            slideChangeTransitionEnd: () => {
-              let swiper = this.$refs.mySwiper.$swiper
-              let activeIndex = swiper.activeIndex
-              this.myInd = activeIndex
-            },
-          },
-        },
-      data: {},
-      iconArr,
-      active: "",
-    }
-  },
-  computed: {
-    swiper() {
-      return this.$refs.mySwiper.$swiper
-    },
-    fixIcon() {
-      let arr = this.iconArr.filter((item) => !!item.display)
-      return arr
-    },
-  },
-  watch: {
-    myInd: {
-      handler(newv) {
-        this.$nextTick(() => {
-          setTimeout(() => {
-            if (this.active == "video") {
-              // 控制当前选中的视频播放
-              let videoDoms = document.querySelectorAll(".videoDom")
-              videoDoms.forEach((v, i) => {
-                if (i === newv) v.play()
-                else v.pause()
-              })
-            }
-          }, 500)
-        })
-      },
-      immediate: true,
-    },
-
-    active(newVal) {
-      let AcDataLength = this.data[newVal].length - 1
-      if (this.myInd > AcDataLength) this.myInd = AcDataLength
-
-      // 判断是否只有一张图片或者视频,ifrm   lengthShow
-      let tempType = this.data[newVal]
-      if (tempType && tempType.length && tempType.length > 1)
-        this.lengthShow = true
-      else this.lengthShow = false
-      if (!newVal) {
-        return
-      }
-      if (!this.$refs.musicBg) {
-        return
-      }
-      // 如果点击的是音频
-      setTimeout(() => {
-        if (newVal == "video") {
-          this.audioAc(false)
-          if (!this.$refs.musicBg.paused) {
-            this.$refs.musicBg.pause()
-          }
-        }
-        // 控制当前选中的视频播放
-        let videoDoms = document.querySelectorAll(".videoDom")
-        videoDoms.forEach((v, i) => {
-          if (i === this.myInd) v.play()
-          else v.pause()
-        })
-      }, 500)
-    },
-  },
-  mounted() {
-    this.getData()
-    document.addEventListener(
-      "WeixinJSBridgeReady",
-      () => {
-        this.autoplay()
-      },
-      false
-    )
-  },
-  methods: {
-    // 点击查看大图
-    lookImg(url) {
-      let dom = this.$refs.viewer.$viewer
-      this.lookPics = [url]
-      dom.show()
-    },
-    // 音频播放完毕
-    overAudio() {
-      console.log("播放声音完毕")
-      this.audioAc(false)
-    },
-    // 音频的状态
-    audioAc(flag) {
-      this.iconArr.forEach((v) => {
-        if (v.id === "audio") v.audioAc = flag
-      })
-    },
-    // 点击切换图片--视频
-    changeActive(id, flag) {
-      if (id === "audio" && flag === false) {
-        this.audioAc(true)
-        this.$refs.musicBg.play()
-        return
-      } else if (id === "audio" && flag === true) {
-        this.audioAc(false)
-        this.$refs.musicBg.pause()
-        return
-      }
-      this.active = id
-    },
-    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 this.$http.get(url)).data
-      this.data = result[this.m]
-      if (!this.data) {
-        return alert("热点解析错误")
-      }
-      this.audio = this.data["backgroundMusic"]
-      if (!this.data.content && this.isMobile) {
-        this.iconArr.pop()
-      }
-      this.iconArr.forEach((item) => {
-        if (this.data[item.id]) {
-          this.active = !this.active ? item.id : this.active
-          item.display = true
-        }
-        // 如果有音频
-        if (item.id === "audio" && this.audio) item.display = true
-      })
-    },
-
-    colseParent(item) {
-      if (this.isMobile) {
-        if (
-          item.indexOf("mp.weixin.qq.com/mp/") > -1 &&
-          this.active === "iframe"
-        ) {
-          window.parent.document.getElementById("closepop").click()
-        }
-      }
-    },
-    fixUrl(item) {
-      let condition =
-        item.indexOf("http://") > -1 || item.indexOf("https://") > -1
-      if (this.isMobile) {
-        if (
-          item.indexOf("mp.weixin.qq.com/mp/") > -1 &&
-          this.active === "iframe"
-        ) {
-          return `https://www.4dmodel.com/SuperTwo/hot_online1/linktoWC.html?url=${encodeURIComponent(
-            item
-          )}`
-        }
-      }
-      if (!condition) {
-        return "https://" + item
-      }
-      return item
-    },
-    slideto(action) {
-      this.swiper[action]()
-    },
-  },
-}
-</script>
-
-<style lang="less" scoped>
-.viewerCla img {
-  display: none;
-}
-.audio {
-  position: fixed;
-  top: -100px;
-  left: -100px;
-  opacity: 0;
-}
-
-.mb-intro {
-  color: #fff;
-  padding: 10px;
-  > p {
-    line-height: 1.5;
-    letter-spacing: 1px;
-    &:first-of-type {
-      font-weight: bold;
-      font-size: 20px;
-      padding-right: 40px;
-    }
-  }
-}
-.home {
-  position: absolute;
-  left: 50%;
-  top: 50%;
-  transform: translate(-50%, -50%);
-  width: 100%;
-  height: 100%;
-  max-width: 1329px;
-  max-height: 848px;
-  background: #E5DFCD;
-  border-top: solid 8px #A10E0C;
-  border-bottom: solid 8px #A10E0C;
-  padding: 28px 100px;
-  box-sizing: border-box;
-  .content {
-    width: 100%;
-    height: 80%;
-    .warpper {
-      width: 100%;
-      height: 100%;
-      .slide {
-        font-size: 0;
-        img,
-        video,
-        iframe {
-          max-height: 570px;
-          border-radius: 14px;
-        }
-
-        iframe {
-          height: 570px;
-          width: 1000px;
-        }
-      }
-    }
-  }
-  .isMobileCon {
-    height: calc(100vh - 90px);
-  }
-
-  .iconarr {
-    z-index: 1999;
-    position: absolute;
-    right: 30px;
-    bottom: calc(20vh - 20px);
-    list-style: none;
-    display: flex;
-    justify-content: flex-end;
-    li {
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      color: #fff;
-      list-style: none;
-      font-size: 14px;
-      width: 90px;
-      height: 32px;
-      line-height: 32px;
-      cursor: pointer;
-      border-radius: 10px;
-      border: solid 1px #fff;
-      margin-right: 10px;
-      span {
-        margin-left: 4px;
-      }
-    }
-    .active {
-      background: #19bbed;
-      border: none;
-    }
-  }
-  .oneChuMusic {
-    opacity: 0;
-    pointer-events: none;
-  }
-  .onlyTxt {
-    display: none !important;
-  }
-  .intro {
-    max-height: 19vh;
-    overflow: auto;
-    width: 70%;
-    color: #fff;
-    margin: 0 auto;
-    > h3 {
-      font-size: 20px;
-      font-weight: 600;
-    }
-    > p {
-      line-height: 1.5;
-      margin-top: 10px;
-      font-size: 16px;
-      text-indent: 32px;
-    }
-  }
-  .ismtop {
-    max-height: 65%;
-    height: 65%;
-    padding: 50px 0;
-    display: flex;
-    flex-direction: column;
-    justify-content: center;
-  }
-}
-
-@media screen and (max-width: 1400px) {
-  .home {
-    overflow-y: auto;
-    overflow-x: hidden;
-    .content {
-      .warpper {
-        .slide {
-          img,
-          video,
-          iframe {
-            max-height: 500px;
-          }
-          img {
-            max-height: 80vh;
-            width: 90%;
-          }
-          iframe {
-            height: 500px;
-          }
-        }
-      }
-    }
-  }
-}
-
-@media screen and (max-width: 1000px) {
-  .home {
-    background: rgba(0, 0, 0, 0.8);
-    .content {
-      .warpper {
-        .slide {
-          width: 100%;
-          img,
-          video,
-          iframe {
-            max-height: none;
-            width: 100%;
-            border-radius: 0;
-          }
-          img {
-            max-height: 80vh;
-            width: 90%;
-          }
-          iframe {
-            width: 100%;
-            height: calc(100vh - 90px);
-          }
-        }
-      }
-    }
-    .iconarr {
-      display: flex;
-      flex-wrap: wrap;
-      list-style: none;
-      margin-right: 0px;
-      position: fixed;
-      bottom: 0px;
-      right: 0px;
-      z-index: 1999;
-      li {
-        width: 70px;
-        margin-bottom: 10px;
-      }
-    }
-  }
-}
-
-@media only screen and (max-width: 906px) and (orientation: landscape) {
-  .home {
-    .content {
-      .warpper {
-        .slide {
-          width: 100%;
-          img,
-          video,
-          iframe {
-            max-width: 70%;
-            max-height: 80vh;
-          }
-          iframe {
-            width: 100%;
-            max-width: unset;
-            height: calc(100vh - 90px);
-          }
-        }
-      }
-    }
-  }
-}
-</style>
-
-<style>
-.swiper-container {
-  width: 100%;
-  height: 100%;
-}
-
-.swiper-pagination-bullet {
-  background: #fff;
-}
-.swiper-slide {
-  text-align: center;
-  font-size: 18px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  transition: 300ms;
-  transform: scale(0.8);
-  position: relative;
-  opacity: 0.5;
-}
-
-.swiper-slide-active,
-.swiper-slide-duplicate-active {
-  transform: scale(1);
-  opacity: 1;
-  z-index: 999;
-}
-
-.swiper-button-prev,
-.swiper-button-next {
-  background: rgba(0, 0, 0, 0.4);
-  padding: 10px 20px;
-  color: #fff !important;
-}
-.swiper-button-prev {
-  left: 0;
-}
-.swiper-button-next {
-  right: 0;
-}
-
-@media screen and (max-width: 500px) {
-  .swiper-slide {
-    width: 100%;
-  }
-}
-</style>

+ 0 - 664
src/views/HomeMobile.vue

@@ -1,664 +0,0 @@
-<template>
-  <div class="hotspot-home">
-    <audio
-      ref="bg-audio"
-      class="bg-audio"
-      :src="bgAudioUrl"
-      loop
-      autoplay
-    />
-
-    <button
-      class="close"
-      @click="onClickClose"
-    >
-      <img
-        src="@/assets/images/close.png"
-        alt="关闭"
-        draggable="false"
-      >
-    </button>
-
-    <div class="title-wrapper">
-      <h1
-        :title="hotspotData.title"
-        v-html="hotspotData.title"
-      />
-      <img
-        src="@/assets/images/title-bottom-line.png"
-        alt=""
-        class="bottom-line"
-      >
-    </div>
-
-    <div
-      v-if="isShowVideos"
-      v-show="!isShowShare"
-      class="swiper-wrapper-mine video-wrap"
-    >
-      <div
-        class="swiper-root"
-      >
-        <div
-          class="swiper-wrapper"
-        >
-          <div
-            v-for="(item, index) in hotspotData.video"
-            :key="index"
-            class="swiper-slide"
-          >
-            <video
-              ref="video"
-              :src="item.url"
-              controls
-              controlslist="nodownload"
-              disablePictureInPicture
-            />
-          </div>
-        </div>
-        <div class="swiper-pagination" />
-        <div class="swiper-button-prev" />
-        <div class="swiper-button-next" />
-      </div>
-    </div>
-
-    <div
-      v-if="isShowModels"
-      class="swiper-wrapper-mine model-wrap"
-    >
-      <div
-        class="swiper-root"
-      >
-        <div
-          class="swiper-wrapper"
-        >
-          <iframe
-            v-for="(item, index) in hotspotData.model"
-            :key="index"
-            :src="item"
-            frameborder="0"
-            class="swiper-slide"
-          />
-        </div>
-        <div class="swiper-pagination" />
-      </div>
-    </div>
-
-    <div
-      v-if="isShowAudios"
-      v-show="!isShowShare"
-      class="swiper-wrapper-mine audio-wrap"
-    >
-      <div
-        class="swiper-root"
-      >
-        <div
-          class="swiper-wrapper"
-        >
-          <div
-            v-for="(item, index) in hotspotData.audio"
-            :key="index"
-            class="swiper-slide"
-          >
-            <audio
-              ref="audio"
-              :src="item.url"
-              controls
-              controlslist="nodownload"
-              disablePictureInPicture
-            />
-          </div>
-        </div>
-        <div class="swiper-pagination" />
-      </div>
-    </div>
-
-    <div
-      v-if="isShowImages"
-      v-show="!isShowShare"
-      class="swiper-wrapper-mine image-wrap"
-    >
-      <div
-        class="swiper-root"
-      >
-        <div
-          v-viewer="{
-            button: true,
-            navbar: false,
-            title: false,
-            toolbar: false,
-            tooltip: false,
-            movable: true,
-            zoomable: true,
-            rotatable: true,
-            scalable: true,
-            transition: false,
-            fullscreen: false,
-            keyboard: true,
-            loop: false,
-          }"
-          class="swiper-wrapper"
-        >
-          <img
-            v-for="(item, index) in hotspotData.images"
-            :key="index"
-            v-lazy="item"
-            class="swiper-slide"
-            alt=""
-            draggable="false"
-          >
-        </div>
-        <div class="swiper-pagination">
-          <!-- <span
-            class="cur"
-          >
-            {{ currentSlideIdx + 1 }}
-          </span>
-          /
-          <span>
-            {{ hotspotData.Images ? hotspotData.images.length : '' }}
-          </span> -->
-        </div>
-        <div class="swiper-button-prev" />
-        <div class="swiper-button-next" />
-      </div>
-    </div>
-
-    <menu>
-      <button
-        v-if="bgAudioUrl"
-        @click="isBgAudioMuted = !isBgAudioMuted"
-      >
-        <img
-          v-show="isBgAudioMuted"
-          class="bg-audio-control"
-          src="@/assets/images/bg-audio-mobile.png"
-          alt=""
-          draggable="false"
-        >
-        <img
-          v-show="!isBgAudioMuted"
-          class="bg-audio-control"
-          src="@/assets/images/bg-audio-mobile-muted.png"
-          alt=""
-          draggable="false"
-        >
-      </button>
-      <!-- <button @click="onClickLike">
-          <img
-            class="like"
-            src="@/assets/images/like-mobile.png"
-            alt=""
-            draggable="false"
-          >
-          <transition name="bubble">
-            <div
-              v-if="isShowPlusOne"
-              class="plus-one"
-            >
-              +1
-            </div>
-          </transition>
-        </button> -->
-      <!-- <button @click="onClickShare">
-        <img
-          class="share"
-          src="@/assets/images/share-mobile.png"
-          alt=""
-          draggable="false"
-        >
-      </button> -->
-    </menu>
-
-    <div class="desc-wrap">
-      <div
-        class="place-holder"
-        @mousedown.prevent
-        @touchstart.prevent
-      />
-      <div class="desc-bg-wrap">
-        <div class="top-bar" />
-        <div
-          class="desc"
-          v-html="descForShow"
-        />
-      </div>
-    </div>
-
-    <div
-      v-if="isShowShare"
-      class="share-wrap"
-    >
-      <img
-        v-click-outside.click="closeCode2d"
-        src="@/assets/images/code2d.png"
-        alt=""
-        class="code"
-        draggable="false"
-      >
-    </div>
-  </div>
-</template>
-
-<script>
-import Swiper from 'swiper/swiper-bundle.esm.js'
-import 'swiper/swiper-bundle.css'
-// import browser from "@/utils/browser";
-
-export default {
-  data() {
-    return {
-      hotspotData: {}, // 热点数据
-
-      bgAudioUrl: "", //背景音频url
-      isBgAudioMuted: false,
-
-      isShowImages: false,
-      isShowVideos: false,
-      isShowModels: false,
-      isShowAudios: false,
-
-      currentSlideIdx: 0,
-      isShowPlusOne: false,
-      isShowShare: false,
-    }
-  },
-  computed: {
-    descForShow() {
-      if (this.isShowImages) {
-        return this.hotspotData.imagesDesc[this.currentSlideIdx] || this.hotspotData.content
-      } else if (this.isShowVideos) {
-        return this.hotspotData.videosDesc[this.currentSlideIdx] || this.hotspotData.content
-      } else {
-        return this.hotspotData.content
-      }
-    },
-  },
-  watch: {
-    isBgAudioMuted: {
-      handler(vNew) {
-        if (vNew) {
-          this.$refs['bg-audio'].pause() // or toggle静音?
-        } else {
-          this.$refs['bg-audio'].play() // or toggle静音?
-        }
-      }
-    }
-  },
-  async mounted() {
-    await this.getData()
-    this.$nextTick(() => {
-      const that = this
-      new Swiper('.swiper-root', {
-        pagination: {
-          el: '.swiper-pagination',
-        },
-        navigation: {
-          nextEl: '.swiper-button-next',
-          prevEl: '.swiper-button-prev',
-        },
-
-        on: {
-          // 自动播放
-          afterInit: function (e) {
-            if (that.isShowVideos) {
-              that.$nextTick(() => {
-                that.$refs.video[0].play()
-              })
-            }
-            if (that.isShowAudios) {
-              that.$nextTick(() => {
-                that.$refs.audio[0].play()
-              })
-            }
-          },
-          slideChange: function(e) {
-            that.currentSlideIdx = e.activeIndex
-
-            // 自动播放
-            if (that.isShowVideos) {
-              for (let index = 0; index < that.$refs.video.length; index++) {
-                if (index !== that.currentSlideIdx) {
-                  that.$refs.video[index].pause()
-                } else {
-                  that.$refs.video[index].play()
-                }
-              }
-            }
-            if (that.isShowAudios) {
-              for (let index = 0; index < that.$refs.audio.length; index++) {
-                if (index !== that.currentSlideIdx) {
-                  that.$refs.audio[index].pause()
-                } else {
-                  that.$refs.audio[index].play()
-                }
-              }
-            }
-          }
-        }
-      })
-    })
-  },
-  methods: {
-    async getData() {
-      let url = `https://super.4dage.com/data/${this.$route.query.id}/hot/js/data.js?time=${Math.random()}`
-      let result = (await this.$http.get(url)).data
-      this.hotspotData = result[this.$route.query.m]
-      if (!this.hotspotData) {
-        return alert("热点解析错误")
-      }
-      console.log('热点数据:', this.hotspotData)
-
-      // this.bgAudioUrl = this.hotspotData.backgroundMusic
-
-      if (this.hotspotData.images && this.hotspotData.images.length) {
-        this.isShowImages = true
-      } else if (this.hotspotData.video && this.hotspotData.video.length) {
-        this.isShowVideos = true
-      } else if (this.hotspotData.model && this.hotspotData.model.length) {
-        this.isShowModels = true
-      } else if (this.hotspotData.backgroundMusic) {
-        this.isShowAudios = true
-        this.hotspotData.audio = [{ url: this.hotspotData.backgroundMusic }]
-      }
-    },
-    onClickClose() {
-      window.parent.document.getElementById('closepop').click()
-    },
-    // onClickLike() {
-    //   const res = globalApi.like()
-    //   if (res && res.then) {
-    //   res.then(() => {
-    //   this.isShowPlusOne = true
-    //   setTimeout(() => {
-    //     this.isShowPlusOne = false
-    //   }, 1000)
-    //   })
-    //   }
-    // },
-    onClickShare() {
-      setTimeout(() => {
-        this.isShowShare = true
-      }, 200)
-    },
-    closeCode2d() {
-      if (this.isShowShare) {
-        this.isShowShare = false
-      }
-    }
-  }
-}
-</script>
-
-<style lang="less" scoped>
-.hotspot-home {
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  color: #F1F3F4;
-  z-index: 0;
-  > .bg-audio {
-    display: none;
-  }
-
-  > button.close {
-    position: absolute;
-    top: 20px;
-    right: 30px;
-    width: 33.5px;
-    height: 33.5px;
-    z-index: 1;
-    > img {
-      width: 100%;
-      height: 100%;
-    }
-  }
-
-  > .title-wrapper {
-    position: absolute;
-    top: 62px;
-    left: 50%;
-    transform: translateX(-50%);
-    width: 90%;
-    z-index: 1;
-    > h1 {
-      width: 100%;
-      font-size: 27.5px;
-      line-height: 1.2em;
-      font-size: 27.5px;
-      font-family: DFLiShuW7;
-      letter-spacing: 2px;
-      text-align: center;
-      display: -webkit-box;
-      -webkit-box-orient: vertical;
-      -webkit-line-clamp: 2;
-      overflow: hidden;
-    }
-    > .bottom-line {
-      position: absolute;
-      top: 100%;
-      left: calc(50% + 10px);
-      transform: translateX(-50%);
-      width: 174px;
-      height: 9.5px;
-    }
-  }
-
-  .swiper-wrapper-mine {
-    position: absolute;
-    top: 150px;
-    left: 0px;
-    width: 100%;
-    height: 250px;
-    z-index: 1;
-    .swiper-root {
-      overflow: hidden;
-      height: 100%;
-      width: 100%;
-      .swiper-wrapper {
-      }
-      .swiper-pagination {
-        position: absolute;
-        top: 100%;
-        left: 50%;
-        transform: translateX(-50%);
-        font-size: 1.33rem;
-        font-family: Inter-Regular, Inter;
-        .cur {
-        }
-      }
-      .swiper-button-prev {
-        left: 10px;
-        width: 20px;
-        background-image: url(../assets/images/arrow-left.png);
-        background-size: contain;
-        background-repeat: no-repeat;
-        background-position: center;
-        &::after {
-          content: '';
-        }
-      }
-      .swiper-button-next {
-        right: 10px;
-        width: 20px;
-        background-image: url(../assets/images/arrow-right.png);
-        background-size: contain;
-        background-repeat: no-repeat;
-        background-position: center;
-        &::after {
-          content: '';
-        }
-      }
-    }
-  }
-  .swiper-wrapper-mine.video-wrap {
-    .swiper-root {
-      .swiper-wrapper {
-        .swiper-slide {
-          > video {
-            width: 100%;
-            height: 100%;
-            background: #000;
-          }
-        }
-      }
-    }
-  }
-  .swiper-wrapper-mine.model-wrap {
-    .swiper-root {
-      .swiper-wrapper {
-      }
-    }
-  }
-  .swiper-wrapper-mine.audio-wrap {
-    .swiper-root {
-      .swiper-wrapper {
-        .swiper-slide {
-          > audio {
-            position: absolute;
-            top: 50%;
-            left: 50%;
-            width: 80%;
-            transform: translate(-50%, -50%);
-          }
-        }
-      }
-    }
-  }
-  .swiper-wrapper-mine.image-wrap {
-    .swiper-root {
-      .swiper-wrapper {
-        > img {
-          width: 100%;
-          height: 100%;
-          object-fit: contain;
-        }
-      }
-    }
-  }
-
-  > menu {
-    position: absolute;
-    top: 415px;
-    left: 50%;
-    transform: translateX(-50%);
-    z-index: 1;
-    > button {
-      display: inline-block;
-      width: 24px;
-      height: 24px;
-      margin-right: 38.5px;
-      position: relative;
-      &:last-of-type{
-        margin-right: initial;
-      }
-      img {
-        width: 100%;
-        height: 100%;
-      }
-      // .plus-one {
-      //   position: absolute;
-      //   top: 0;
-      //   right: 0;
-      //   transform: translate(50%, -50%);
-      // }
-    }
-  }
-
-  > .desc-wrap {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    overflow: auto;
-    > .place-holder {
-      width: 100%;
-      height: 450px;
-    }
-    > .desc-bg-wrap {
-      z-index: 2;
-      position: absolute;
-      top: 450px;
-      left: 50%;
-      transform: translateX(-50%);
-      width: calc(100vw - 11px * 2);
-      height: calc((100vw - 11px * 2) * 1.7);
-      background-image: url(@/assets/images/bg-mobile.png);
-      background-size: contain;
-      background-repeat: no-repeat;
-      background-position: center center;
-      > .top-bar {
-        position: absolute;
-        top: 20px;
-        left: 50%;
-        transform: translateX(-50%);
-        width: 127px;
-        height: 4px;
-        background: #F4D49F;
-        border-radius: 2px;
-      }
-      > .desc {
-        position: absolute;
-        font-size: 16px;
-        line-height: 26px;
-        font-family: Adobe Heiti Std;
-        top: 77px;
-        bottom: 40px;
-        left: 26px;
-        right: 26px;
-        width: calc(100% - 26px * 2);
-        overflow: auto;
-      }
-    }
-  }
-
-  .share-wrap {
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 1;
-    > img.code {
-      position: absolute;
-      top: 190px;
-      left: 50%;
-      transform: translateX(-50%);
-      width: 170px;
-      height: 170px;
-    }
-  }
-}
-
-/deep/.swiper-pagination-bullet-active {
-  background: #a10e0c;
-}
-
-// .bubble-enter {
-//   opacity: 0;
-//   top: 1rem !important;
-// }
-// .bubble-enter-to {
-//   opacity: 1;
-//   top: 0 !important;
-// }
-// .bubble-enter-active {
-//   transition: all 0.5s;
-// }
-// .bubble-leave {
-//   opacity: 1;
-//   top: 0 !important;
-// }
-// .bubble-leave-to {
-//   opacity: 0;
-//   top: -1rem !important;
-// }
-// .bubble-leave-active {
-//   transition: all 0.5s;
-// }
-
-::-webkit-scrollbar { width: 0; height: 0; } /*宽度是对垂直滚动条而言,高度是对水平滚动条而言*/
-</style>

+ 16 - 5
src/views/HomeWeb.vue

@@ -15,7 +15,7 @@
 </template>
 
 <script>
-// import browser from "@/utils/browser";
+import browser from "@/utils/browser"
 import quizData from "@/quizData.js"
 
 export default {
@@ -65,7 +65,11 @@ export default {
         return item.id === newId
       })
       this.setQuestionInfo(quizInfo)
-      this.$router.push({ name: 'QuestionView' })
+      if (browser.mobile) {
+        this.$router.push({ name: 'QuestionViewMobile' })
+      } else {
+        this.$router.push({ name: 'QuestionView' })
+      }
     } else { //答过这个点位的题,可能要找到最近答的那道题,恢复现场
       const latestRecord = recordOnThisHotspot.reduce((accu, curr) => {
         if (new Date(accu.updateTime).getTime() <= new Date(curr.updateTime).getTime()) {
@@ -80,7 +84,11 @@ export default {
           return item.id === newId
         })
         this.setQuestionInfo(quizInfo)
-        this.$router.push({ name: 'QuestionView' })
+        if (browser.mobile) {
+          this.$router.push({ name: 'QuestionViewMobile' })
+        } else {
+          this.$router.push({ name: 'QuestionView' })
+        }
       } else {
         const quizInfo = quizData.find((item) => {
           return item.id === latestRecord.num
@@ -89,8 +97,11 @@ export default {
         this.setAnswerRecord(latestRecord)
         this.setIsSubmitted(true)
         this.setQuestionInfo(quizInfo)
-        // if (quizInfo.questionType === '判断题') {
-        this.$router.push({ name: 'QuestionView' })
+        if (browser.mobile) {
+          this.$router.push({ name: 'QuestionViewMobile' })
+        } else {
+          this.$router.push({ name: 'QuestionView' })
+        }
       }
     }
   },

+ 139 - 7
src/views/QuestionInner.vue

@@ -37,7 +37,10 @@
             alt=""
             draggable="false"
           >
-          <span class="right-tip-text">恭喜你,回答正确</span>
+          <span
+            v-show="questionInfo.rightOptionIdx.length === 1"
+            class="right-tip-text"
+          >恭喜你,回答正确</span>
         </div>
         <div
           v-show="isSubmitted && selectedIdxList[index] && !questionInfo.rightOptionIdx.includes(index)"
@@ -49,7 +52,10 @@
             alt=""
             draggable="false"
           >
-          <span class="wrong-tip-text">很遗憾,回答错误</span>
+          <span
+            v-show="questionInfo.rightOptionIdx.length === 1"
+            class="wrong-tip-text"
+          >很遗憾,回答错误</span>
         </div>
       </button>
     </template>
@@ -84,9 +90,9 @@
               :key="indexRight"
               :ref="`${indexLeft}-${indexRight}`"
               x1="0"
-              :y1="`calc((100% + 64px) / ${questionInfo.answerOptions.left.length + 1} * ${indexLeft + 1} - 64px / 2)`"
+              :y1="`calc((100% + ${isMobile ? '32' : '64'}px) / ${questionInfo.answerOptions.left.length + 1} * ${indexLeft + 1} - ${isMobile ? '32' : '64'}px / 2)`"
               x2="100%"
-              :y2="`calc((100% + 64px) / ${questionInfo.answerOptions.right.length + 1} * ${indexRight + 1} - 64px / 2)`"
+              :y2="`calc((100% + ${isMobile ? '32' : '64'}px) / ${questionInfo.answerOptions.right.length + 1} * ${indexRight + 1} - ${isMobile ? '32' : '64'}px / 2)`"
               stroke-width="2px"
               :stroke="lineColor(indexLeft, indexRight)"
             />
@@ -135,8 +141,6 @@
 </template>
 
 <script>
-// import browser from "@/utils/browser";
-// import * as d3 from "d3"
 
 export default {
   props: [
@@ -331,7 +335,7 @@ export default {
     &.submitted {
       pointer-events: none;
     }
-    &.submitted.selected.rightOption {
+    &.submitted.rightOption {
       background-image: url(@/assets/images/option-correct-bg.png);
       background-size: cover;
       background-repeat: no-repeat;
@@ -472,4 +476,132 @@ export default {
     }
   }
 }
+
+.mobile {
+  .question-inner {
+    flex: 0 0 auto;
+    width: calc(100% - 30px * 2);
+    margin-top: 0;
+    > .type {
+      padding-left: 6px;
+      padding-right: 6px;
+      font-size: 16px;
+    }
+    > p.question {
+      margin-top: 10px;
+      padding-left: 6px;
+      padding-right: 6px;
+      font-size: 14px;
+      line-height: 1.5em;
+      max-height: 6em;
+      overflow: auto;
+    }
+    > button.option {
+      margin-top: 5px;
+      height: 32px;
+      padding-left: 6px;
+      padding-right: 35px;
+      padding-top: 5px;
+      font-size: 14px;
+      &.notSubmitted:hover {
+        color: #693D2F;
+      }
+      &.notSubmitted.selected {
+        background-image: url(@/assets/images/option-correct-bg-mobile.png);
+      }
+      &.submitted {
+      }
+      &.submitted.rightOption {
+        background-image: url(@/assets/images/option-correct-bg-mobile.png);
+      }
+      &.submitted.selected.wrongOption {
+        background-image: url(@/assets/images/option-wrong-bg-mobile.png);
+      }
+      > .option-text {
+        &::before {
+        }
+      }
+      > .result-tip {
+        > img.correct-icon {
+          width: 11px;
+          height: 8px;
+          margin-right: 5px;
+        }
+        > img.wrong-icon {
+          width: 11px;
+          height: 11px;
+          margin-right: 5px;
+        }
+        > .right-tip-text {
+          font-size: 14px;
+        }
+        > .wrong-tip-text {
+          font-size: 14px;
+        }
+      }
+    }
+    > .line-quiz-wrapper {
+      margin-top: 10px;
+      height: 170px;
+      > .left {
+        width: 100px;
+        > button {
+          width: 100px;
+          height: 32px;
+          border-radius: 16px;
+          font-size: 16px;
+          &:hover {
+            background: initial;
+          }
+          &.active {
+            background: #FFE5BA;
+          }
+        }
+      }
+      > .svg-wrapper {
+        left: 100px;
+        width: calc(100% - 100px * 2);
+        > svg {
+          width: 100%;
+          height: 100%;
+          > g {
+            width: 100%;
+            height: 100%;
+            > line {
+
+            }
+          }
+        }
+      }
+      > .right {
+        width: 100px;
+        > button {
+          width: 100px;
+          height: 32px;
+          border-radius: 16px;
+          font-size: 16px;
+          &:hover {
+            background: initial;
+          }
+          &.active {
+            background: #FFE5BA;
+          }
+        }
+      }
+      > .result-tip {
+        top: 94%;
+        &.correct {
+        }
+        &.wrong {
+        }
+        > img {
+          width: 12px;
+          height: 12px;
+          margin-left: 10px;
+          margin-bottom: 1px;
+        }
+      }
+    }
+  }
+}
 </style>

+ 295 - 0
src/views/QuestionViewMobile.vue

@@ -0,0 +1,295 @@
+<template>
+  <div
+    class="question-view"
+    :style="{
+      width: initialWrapperWidth + 'px',
+      height: initialWrapperHeight + 'px',
+      transform: wrapperTransformCss,
+    }"
+  >
+    <button
+      class="close"
+      @click="onClickClose"
+    >
+      <img
+        src="@/assets/images/close.png"
+        alt="关闭"
+        draggable="false"
+      >
+    </button>
+    <div class="title-wrapper">
+      <h1>知识问答</h1>
+    </div>
+    <QuestionInner
+      ref="question-inner"
+      @submit="onSubmit"
+    />
+    <div
+      v-show="isSubmitted"
+      class="answer-desc-inline"
+    >
+      <p
+        v-if="questionInfo.descText"
+        class="desc"
+      >
+        {{ questionInfo.descText }}
+      </p>
+      <img
+        v-for="(item, index) in questionInfo.descImg"
+        :key="index"
+        v-viewer="{
+          button: true,
+          navbar: false,
+          title: false,
+          toolbar: false,
+          tooltip: false,
+          movable: true,
+          zoomable: true,
+          rotatable: true,
+          scalable: true,
+          transition: false,
+          fullscreen: false,
+          keyboard: true,
+          loop: false,
+        }"
+        :src="require(`@/assets/images/quiz-img/${questionInfo.id}-${item}`)"
+        alt=""
+        class="desc-img"
+      >
+    </div>
+    <button
+      v-show="!isSubmitted && (questionInfo?.questionType === '多选题' || questionInfo.questionType === '连线题') && $refs['question-inner']?.canSubmit"
+      class="submit"
+      @click="onSubmit"
+    >
+      提交答案
+    </button>
+    <div
+      v-show="isSubmitted"
+      class="button-wrapper-submitted"
+    >
+      <button
+        v-show="!$refs['question-inner']?.isCorrect"
+        class="retry"
+        @click="onClickRetry"
+      >
+        重新答题
+      </button>
+      <button
+        v-if="remainingQuestionNumber"
+        class="next"
+        @click="onClickNext"
+      >
+        下一题({{ remainingQuestionNumber }})
+      </button>
+    </div>
+  </div>
+</template>
+
+<script>
+// import browser from "@/utils/browser";
+import QuestionInner from "@/views/QuestionInner.vue"
+import quizData from "@/quizData.js"
+
+export default {
+  components: {
+    QuestionInner,
+  },
+  props: [
+  ],
+  data() {
+    return {
+    }
+  },
+  computed: {
+    ...globalMapState([
+      'questionInfo',
+      'isSubmitted',
+    ]),
+    remainingQuestionNumber() {
+      return globalUtils.getRemainingQuestionNumber(this.questionInfo.id)
+    },
+    initialWrapperWidth() {
+      return 338
+    },
+    initialWrapperHeight() {
+      return 596
+    },
+    wrapperTransformCss() {
+      const WHRateViewport = window.innerWidth / window.innerHeight
+      const WHRateComp = this.initialWrapperWidth / this.initialWrapperHeight
+      if (WHRateViewport >= WHRateComp) { // 视口矮宽
+        return `translate(-50%, -50%) scale(${window.innerHeight / this.initialWrapperHeight * 0.9})`
+      } else {
+        return `translate(-50%, -50%) scale(${window.innerWidth / this.initialWrapperWidth * 0.9})`
+      }
+    }
+  },
+  watch: {
+  },
+  async mounted() {
+  },
+  methods: {
+    ...globalMapMutations([
+      'setIsSubmitted',
+      'setAnswerRecord',
+      'setQuestionInfo',
+    ]),
+    onClickClose() {
+      window.parent.document.getElementById('closepop').click()
+    },
+    onSubmit() {
+      if (this.$refs['question-inner']?.canSubmit) {
+        this.setIsSubmitted(true)
+        globalApi.submitAnswer(
+          this.$refs['question-inner']?.isCorrect,
+          this.questionInfo.id,
+          this.$refs['question-inner']?.selectedIdxList,
+          this.questionInfo.badgeTypeCode,
+        )
+      }
+    },
+    onClickRetry() {
+      this.setIsSubmitted(false)
+      this.setAnswerRecord(null)
+      this.$refs['question-inner'].resetSelectedIdxList()
+    },
+    onClickNext() {
+      this.setIsSubmitted(false)
+      this.setAnswerRecord(null)
+
+      const newId = globalUtils.getNextQuestionId(this.questionInfo.id)
+      const quizInfo = quizData.find((item) => {
+        return item.id === newId
+      })
+      this.setQuestionInfo(quizInfo)
+
+      this.$refs['question-inner'].resetSelectedIdxList()
+    },
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.question-view {
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  transform: translate(-50%, -50%);
+  background-image: url(@/assets/images/share-bg-mobile.png);
+  background-size: contain;
+  background-repeat: no-repeat;
+  background-position: center center;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  > button.close {
+    position: absolute;
+    top: 40px;
+    right: 25px;
+    width: 21px;
+    height: 21px;
+    > img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+  > .title-wrapper {
+    flex: 0 0 auto;
+    text-align: center;
+    margin-top: 38px;
+    width: 200px;
+    height: 55px;
+    background-image: url(@/assets/images/title-decorator-mobile.png);
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center center;
+    > h1 {
+      font-size: 24px;
+      font-family: LiSu-Regular, LiSu;
+      font-weight: 400;
+      line-height: 42px;
+      color: #9A2D0A;
+      background: linear-gradient(177deg, #9A2D0A 0%, #D1672B 100%);
+      background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  }
+  > .answer-desc-inline {
+    margin-top: 10px;
+    flex: 1 0 1px;
+    margin-bottom: 110px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    width: calc(100% - 30px * 2);
+    overflow: auto;
+    padding-left: 6px;
+    padding-right: 6px;
+    > p.desc {
+      overflow: auto;
+      flex: 0 0 auto;
+      font-size: 14px;
+      font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+      font-weight: 400;
+      color: #A4573F;
+      line-height: 17px;
+      letter-spacing: 1px;
+    }
+    > img.desc-img {
+      margin-top: 10px;
+      width: 100%;
+    }
+  }
+  > button.submit {
+    flex: 0 0 auto;
+    position: absolute;
+    bottom: 60px;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 116px;
+    height: 31px;
+    background-image: url(@/assets/images/btn-main-bg.png);
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center center;
+    font-size: 16px;
+    font-family: LiSu-Regular, LiSu;
+    font-weight: 400;
+    color: #FFFFFF;
+  }
+  > .button-wrapper-submitted {
+    flex: 0 0 auto;
+    position: absolute;
+    bottom: 60px;
+    left: 50%;
+    transform: translateX(-50%);
+    display: flex;
+    justify-content: center;
+    > button {
+      width: 116px;
+      height: 31px;
+      font-size: 16px;
+      font-family: LiSu-Regular, LiSu;
+      margin-right: 20px;
+      font-weight: 400;
+      background-size: contain;
+      background-repeat: no-repeat;
+      background-position: center center;
+      margin-right: 15px;
+      display: inline-block;
+      &:last-of-type {
+        margin-right: 0;
+      }
+      &.retry {
+        background-image: url(@/assets/images/btn-normal-bg.png);
+        color: #8F4831;
+      }
+      &.next {
+        background-image: url(@/assets/images/btn-main-bg.png);
+        color: #fff;
+      }
+    }
+  }
+}
+</style>