任一存 2 lat temu
commit
13ab2776f4

+ 3 - 0
.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 3 - 0
.env.dev

@@ -0,0 +1,3 @@
+CLI_MODE=dev
+NODE_ENV=development
+PUBLIC_PATH=/

+ 3 - 0
.env.test

@@ -0,0 +1,3 @@
+CLI_MODE=test
+NODE_ENV=production
+PUBLIC_PATH=/hotspot/

+ 57 - 0
.eslintrc.js

@@ -0,0 +1,57 @@
+// ESLint 检查 .vue 文件需要单独配置编辑器:
+// https://eslint.vuejs.org/user-guide/#editor-integrations
+module.exports = {
+  root: true,
+  env: {
+    browser: true,
+    commonjs: true,
+    es6: true,
+    jest: true,
+    jquery: true,
+    node: true,
+  },
+  'extends': [
+    'eslint:recommended',
+    // "plugin:vue/base",
+    'plugin:vue/recommended',
+  ],
+  parserOptions: {
+    parser: 'babel-eslint'
+    // "parser": "@babel/eslint-parser"
+  },
+  rules: {
+    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+    'semi': ['error', 'never'],
+    "no-unused-vars": ["warn", {
+      "vars": "all",
+      "args": "after-used",
+      "ignoreRestSiblings": false
+    }],
+    "keyword-spacing": ["error", { "before": true, "after": true }],
+    "object-curly-spacing": ["error", "always"],
+    "space-infix-ops": ["error"],
+    'key-spacing': ["error", {
+      "mode": "strict"
+    }],
+    "comma-spacing": ["error", { "before": false, "after": true }],
+    "func-call-spacing": ["error", "never"],
+    "semi-spacing": ["error", { "before": false, "after": true }],
+    "space-before-blocks": ["error", "always"],
+    'no-trailing-spaces': 'error',
+    'no-multi-spaces': 'error',
+    "indent": ["error", 2],
+    'no-empty': 'off',
+    // 默认不启用:为了避免细微的 bug,最好直接从 Object.prototype 调用挂载于prototype上的方法方法。例如,foo.hasOwnProperty("bar") 应该替换为 Object.prototype.hasOwnProperty.call(foo, "bar")。
+    'no-prototype-builtins': "off",
+  },
+  globals: {
+    api: true,
+    config: true,
+    mapState: true,
+    mapGetters: true,
+    mapMutations: true,
+    store: true,
+    utils: true,
+  }
+}

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
+.DS_Store
+node_modules
+/dist
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 24 - 0
README.md

@@ -0,0 +1,24 @@
+# hotspot
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}

Plik diff jest za duży
+ 26480 - 0
package-lock.json


+ 33 - 0
package.json

@@ -0,0 +1,33 @@
+{
+  "name": "hotspot",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve --mode dev",
+    "build-test": "vue-cli-service build --mode test",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "axios": "^0.20.0",
+    "core-js": "^3.6.5",
+    "v-viewer": "^1.5.1",
+    "vue": "^2.6.11",
+    "swiper": "^9.0.3",
+    "vue-awesome-swiper": "^4.1.1",
+    "vue-lazyload": "^1.3.3",
+    "vue-router": "^3.2.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^6.2.2",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "vue-template-compiler": "^2.6.11"
+  }
+}

+ 16 - 0
public/index.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title><%= htmlWebpackPlugin.options.title %></title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 22 - 0
src/App.vue

@@ -0,0 +1,22 @@
+<template>
+  <div id="app">
+    <router-view/>
+  </div>
+</template>
+
+<style lang="less">
+html,body{
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+*{
+  margin: 0;
+  padding: 0;
+}
+#app {
+  width: 100%;
+  height: 100%;
+}
+
+</style>

+ 26 - 0
src/assets/base.css

@@ -0,0 +1,26 @@
+.viewer-title {
+  display: none !important;
+}
+
+.viewer-prev {
+  display: none !important;
+}
+
+.viewer-next {
+  display: none !important;
+}
+
+.viewer-navbar {
+  display: none !important;
+}
+
+.viewer-close {
+  display: none !important;
+}
+
+@media screen and (max-width: 800px) {
+  .viewer-footer {
+    bottom: auto;
+    top: 10px;
+  }
+}

BIN
src/assets/images/IMGerror.png


BIN
src/assets/images/arrow-left.png


BIN
src/assets/images/arrow-right.png


BIN
src/assets/images/audio-icon.png


BIN
src/assets/images/bg.png


BIN
src/assets/images/close-thin.png


BIN
src/assets/images/close.png


BIN
src/assets/images/iframe-icon.png


BIN
src/assets/images/img-icon.png


BIN
src/assets/images/like.png


BIN
src/assets/images/loading.gif


BIN
src/assets/images/model-icon.png


BIN
src/assets/images/share.png


BIN
src/assets/images/title-bottom-line.png


BIN
src/assets/images/txt-icon.png


BIN
src/assets/images/video-icon.png


BIN
src/assets/images/音量.png


+ 60 - 0
src/assets/style/my-reset.css

@@ -0,0 +1,60 @@
+*,
+*::before,
+*::after {
+  /* 阻止safari在用户交互设置一些元素的背景色 */
+  -webkit-tap-highlight-color: transparent;
+  box-sizing: border-box;
+}
+
+html {
+  overflow: hidden;
+  touch-action: none;
+  scroll-behavior: smooth; /* MDN: When this property is specified on the root element, it applies to the viewport instead. This property specified on the body element will not propagate to the viewport.(???) */
+  height: 100%;
+}
+
+body {
+  text-align: justify;
+  height: 100%;
+  overflow: hidden;
+}
+
+a {
+  color: initial;
+  text-decoration: initial;
+  outline: none;
+}
+
+button {
+  padding: 0;
+  cursor: pointer;
+  background-color: initial;
+  border: initial;
+  outline: none;
+  white-space: pre;
+}
+
+img {
+  user-select: none;
+}
+
+menu {
+  list-style-type: initial;
+}
+
+li {
+  display: initial;
+}
+
+input {
+  outline: initial;
+  background: initial;
+  border: initial;
+  border-radius: initial;
+  width: initial;
+  height: initial;
+}
+
+td {
+  vertical-align: inherit;
+}

+ 48 - 0
src/assets/style/reset.css

@@ -0,0 +1,48 @@
+/* http://meyerweb.com/eric/tools/css/reset/ 
+   v2.0 | 20110126
+   License: none (public domain)
+*/
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed, 
+figure, figcaption, footer, header, hgroup, 
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+	margin: 0;
+	padding: 0;
+	border: 0;
+	font-size: 100%;
+	font: inherit;
+	vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure, 
+footer, header, hgroup, menu, nav, section {
+	display: block;
+}
+body {
+	line-height: 1;
+}
+ol, ul {
+	list-style: none;
+}
+blockquote, q {
+	quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+	content: '';
+	content: none;
+}
+table {
+	border-collapse: collapse;
+	border-spacing: 0;
+}

+ 31 - 0
src/main.js

@@ -0,0 +1,31 @@
+import "@/assets/style/reset.css"
+import "@/assets/style/my-reset.css"
+import Vue from 'vue'
+import App from './App.vue'
+import router from './router'
+import axios from 'axios'
+import 'viewerjs/dist/viewer.css'
+import Viewer from 'v-viewer'
+// 图片懒加载
+import VueLazyLoad from 'vue-lazyload'
+
+// 禁用上下文菜单
+document.oncontextmenu = function(e) {
+  e.preventDefault()
+}
+
+Vue.use(VueLazyLoad, {
+  error: require('@/assets/images/IMGerror.png'),
+  loading: require('@/assets/images/loading.gif')
+})
+
+Vue.config.productionTip = false
+Vue.prototype.$http = axios
+
+Vue.use(Viewer)
+
+import './assets/base.css'
+new Vue({
+  router,
+  render: h => h(App)
+}).$mount('#app')

+ 31 - 0
src/router/index.js

@@ -0,0 +1,31 @@
+import Vue from 'vue'
+import VueRouter from 'vue-router'
+// import Home from '../views/Home.vue'
+import HomeWeb from '../views/HomeWeb.vue'
+import HomeMobile from '../views/HomeMobile.vue'
+
+Vue.use(VueRouter)
+
+const routes = [
+  // {
+  //   path: '/',
+  //   name: 'Home',
+  //   component: Home
+  // },
+  {
+    path: '/web',
+    name: 'HomeWeb',
+    component: HomeWeb
+  },
+  {
+    path: '/mobile',
+    name: 'HomeMobile',
+    component: HomeMobile
+  },
+]
+
+const router = new VueRouter({
+  routes
+})
+
+export default router

+ 29 - 0
src/utils/browser.js

@@ -0,0 +1,29 @@
+function versions () {
+  var u = window.navigator.userAgent
+  return {
+    // IE内核
+    trident: u.indexOf('Trident') > -1,
+    // opera内核
+    presto: u.indexOf('Presto') > -1,
+    // 苹果、谷歌内核
+    webKit: u.indexOf('AppleWebKit') > -1,
+    // 火狐内核
+    gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') === -1,
+    // 是否为移动终端 / Tablets use desktop version
+    mobile: (/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) && !(/Tablet|iPad/i.test(navigator.userAgent)),
+    // ios终端
+    ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),
+    // android终端或者uc浏览器
+    android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1,
+    // 是否为iPhone或者安卓QQ浏览器
+    iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1,
+    // 是否为iPad
+    iPad: u.indexOf('iPad') > -1,
+    // 是否为web应用程序,没有头部与底部
+    webApp: u.indexOf('Safari') === -1,
+    // 是否为微信浏览器
+    weixin: ~u.indexOf('MicroMessenger')
+  }
+}
+
+export default versions()

+ 642 - 0
src/views/Home.vue

@@ -0,0 +1,642 @@
+<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>

+ 373 - 0
src/views/HomeMobile.vue

@@ -0,0 +1,373 @@
+<template>
+  <div class="hotspot-home">
+    <button
+      class="close"
+      @click="onClickClose"
+    >
+      <img
+        src="@/assets/images/close-thin.png"
+        alt="关闭"
+        draggable="false"
+      >
+    </button>
+
+    <div
+      v-if="isShowVideos"
+      class="swiper-wrapper-mine video-wrap"
+    >
+      <div
+        class="swiper-root 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
+            class="swiper-slide"
+          >
+            <video
+              ref="video"
+              :src="hotspotData.video[0].url"
+              controls
+              controlslist="nodownload"
+              disablePictureInPicture
+            />
+          </div>
+          <div
+            class="swiper-slide"
+          >
+            <video
+              ref="video"
+              :src="hotspotData.video[0].url"
+              controls
+              controlslist="nodownload"
+              disablePictureInPicture
+            />
+          </div> -->
+        </div>
+        <div class="swiper-pagination">
+          <!-- <span class="cur">{{ currentSlideIdx + 1 }}</span> / <span>{{ typesForShow[currentTabIdx].list.length }}</span> -->
+        </div>
+        <!-- <div class="swiper-button-prev" />
+        <div class="swiper-button-next" /> -->
+      </div>
+    </div>
+
+    <div
+      v-show="isShowImages"
+      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>
+
+    <div class="title-wrap">
+      <h1
+        :title="hotspotData.title"
+        v-html="hotspotData.title"
+      />
+    </div>
+
+    <p
+      class="desc"
+      v-html="descForShow"
+    />
+  </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: {}, // 热点数据
+      audioUrl: "", //背景音频url
+      isShowImages: false,
+      isShowVideos: false,
+      currentSlideIdx: 0,
+    }
+  },
+  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 ''
+      }
+    },
+  },
+  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.typesForShow[vNew].key === 'audio') {
+            //   that.$nextTick(() => {
+            //     that.$refs['audio-comp'][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.typesForShow[vNew].key === 'audio') {
+            //   for (let index = 0; index < that.$refs['audio-comp'].length; index++) {
+            //     if (index !== that.currentSlideIdx) {
+            //       that.$refs['audio-comp'][index].pause()
+            //     } else {
+            //       that.$refs['audio-comp'][index].play()
+            //     }
+            //   }
+            // }
+          }
+        }
+      })
+    })
+  },
+  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.audioUrl = 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
+      }
+    },
+    onClickClose() {
+      window.parent.document.getElementById('closepop').click()
+    },
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.hotspot-home {
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.8);
+  > button.close {
+    position: absolute;
+    top: 15px;
+    right: 15px;
+    width: 28px;
+    height: 28px;
+    > img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  .swiper-wrapper-mine {
+    position: absolute;
+    left: 0;
+    top: 25%;
+    width: 100%;
+    height: 35.6%;
+    .swiper-root {
+      overflow: hidden;
+      height: 100%;
+      width: 100%;
+      .swiper-wrapper {
+      }
+      .swiper-pagination {
+        position: absolute;
+        top: 100%;
+        left: 50%;
+        transform: translateX(-50%);
+      }
+      // .swiper-button-prev {
+      //   left: calc(-1.67rem - 1.83rem);
+      //   width: 1.83rem;
+      //   height: 3.58rem;
+      //   background-image: url(../assets/images/arrow-left.png);
+      //   background-size: contain;
+      //   &::after {
+      //     content: '';
+      //   }
+      // }
+      // .swiper-button-next {
+      //   right: calc(-1.67rem - 1.83rem);
+      //   width: 1.83rem;
+      //   height: 3.58rem;
+      //   background-image: url(../assets/images/arrow-right.png);
+      //   background-size: contain;
+      //   &::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 {
+  //   width: calc(100% - 1.67rem * 2 - 1.83rem * 2 - 1.67rem * 2);
+  //   height: 30rem;
+  //   position: absolute;
+  //   left: 50%;
+  //   top: 50%;
+  //   transform: translate(-50%, -70%);
+  //   .swiper-root {
+  //     width: 100%;
+  //     .swiper-wrapper {
+  //     }
+  //   }
+  // }
+  .swiper-wrapper-mine.image-wrap {
+    .swiper-root {
+      .swiper-wrapper {
+        > img {
+          width: 100%;
+          height: 100%;
+          object-fit: contain;
+        }
+      }
+    }
+  }
+
+  > .title-wrap {
+    position: absolute;
+    width: 100%;
+    overflow: auto;
+    top: 66%;
+    > h1 {
+      padding: 0 26px;
+      white-space: pre;
+      font-size: 24px;
+      font-weight: bold;
+      color: #FFFFFF;
+    }
+  }
+  .desc {
+    position: absolute;
+    left: 24px;
+    right: 24px;
+    bottom: 30px;
+    height: 22%;
+    overflow: auto;
+    font-size: 16px;
+    color: #FFFFFF;
+    line-height: 19px;
+    padding-right: 10px;
+  }
+}
+
+/deep/.swiper-pagination-bullet {
+  opacity: 1;
+  background: #666;
+}
+/deep/.swiper-pagination-bullet-active {
+  background: #a10e0c;
+}
+</style>

+ 490 - 0
src/views/HomeWeb.vue

@@ -0,0 +1,490 @@
+<template>
+  <div class="hotspot-home">
+    <button
+      class="close"
+      @click="onClickClose"
+    >
+      <img
+        src="@/assets/images/close.png"
+        alt="关闭"
+        draggable="false"
+      >
+    </button>
+    <div
+      class="bg-wrapper"
+      :style="{
+        backgroundImage: `url(${bgImg})`,
+      }"
+    >
+      <h1
+        :title="hotspotData.title"
+        :style="{
+          backgroundImage: `url(${titleBottomLine})`,
+        }"
+        v-html="hotspotData.title"
+      />
+      <div class="desc">
+        <p>路口五金是雷锋精神</p>
+        <p>开口就是浪费大家</p>
+        <p>可进行分类算法</p>
+        <p>
+          <span v-html="descForShow" />
+        </p>
+      </div>
+      <menu>
+        <!-- <button>
+        <img
+          class=""
+          src=""
+          alt=""
+          draggable="false"
+        >
+      </button> -->
+        <button @click="onClickLike">
+          <img
+            class="like"
+            src="@/assets/images/like.png"
+            alt=""
+            draggable="false"
+          >
+          <transition name="bubble">
+            <div
+              v-if="isShowPlusOne"
+              class="plus-one"
+            >
+              +1
+            </div>
+          </transition>
+        </button>
+        <button>
+          <img
+            class="share"
+            src="@/assets/images/share.png"
+            alt=""
+            draggable="false"
+          >
+        </button>
+      </menu>
+
+      <div
+        v-if="isShowVideos"
+        class="swiper-wrapper-mine video-wrap"
+      >
+        <div
+          class="swiper-root 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">
+          <!-- <span class="cur">{{ currentSlideIdx + 1 }}</span> / <span>{{ typesForShow[currentTabIdx].list.length }}</span> -->
+          </div>
+          <div class="swiper-button-prev" />
+          <div class="swiper-button-next" />
+        </div>
+      </div>
+
+      <div
+        v-show="isShowImages"
+        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>
+    </div>
+  </div>
+</template>
+
+<script>
+import Swiper from 'swiper/swiper-bundle.esm.js'
+import 'swiper/swiper-bundle.css'
+import bgImg from "@/assets/images/bg.png"
+import titleBottomLine from "@/assets/images/title-bottom-line.png"
+// import browser from "@/utils/browser";
+
+export default {
+  data() {
+    return {
+      hotspotData: {}, // 热点数据
+      audioUrl: "", //背景音频url
+      isShowImages: false,
+      isShowVideos: false,
+      currentSlideIdx: 0,
+      bgImg,
+      titleBottomLine,
+      isShowPlusOne: 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 ''
+      }
+    },
+  },
+  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.typesForShow[vNew].key === 'audio') {
+            //   that.$nextTick(() => {
+            //     that.$refs['audio-comp'][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.typesForShow[vNew].key === 'audio') {
+            //   for (let index = 0; index < that.$refs['audio-comp'].length; index++) {
+            //     if (index !== that.currentSlideIdx) {
+            //       that.$refs['audio-comp'][index].pause()
+            //     } else {
+            //       that.$refs['audio-comp'][index].play()
+            //     }
+            //   }
+            // }
+          }
+        }
+      })
+    })
+  },
+  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.audioUrl = 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
+        this.hotspotData.video = [...this.hotspotData.video, ...this.hotspotData.video]
+      }
+    },
+    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)
+      // })
+      // }
+    },
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.hotspot-home {
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  transform: translate(-50%, -50%);
+  width: 1350px;
+  height: 810px;
+  padding: 0 70px 0 0;
+  color: #F1F3F4;
+  > button.close {
+    position: absolute;
+    top: 10px;
+    right: 0px;
+    width: 58px;
+    height: 58px;
+    > img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+  > .bg-wrapper {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center center;
+    > h1 {
+      position: absolute;
+      top: 211px;
+      left: 44px;
+      max-width: 418px;
+      font-size: 28px;
+      font-family: DFLiShuW7;
+      overflow: hidden;
+      white-space: pre;
+      text-overflow: ellipsis;
+      letter-spacing: 5px;
+      padding-left: 10px;
+      padding-right: 10px;
+      padding-bottom: 24px;
+      background-size: contain;
+      background-repeat: no-repeat;
+      background-position: center bottom;
+    }
+    > .desc {
+      position: absolute;
+      top: 347px;
+      left: 80px;
+      width: 362px;
+      font-size: 16px;
+      line-height: 26px;
+      > p {
+        margin-bottom: 10px;
+        position: relative;
+      }
+      > p.intro {
+        overflow: auto;
+        max-height: 200px;
+      }
+      > p::before {
+        position: absolute;
+        left: -24px;
+        top: calc(6px);
+        content: '';
+        display: inline-block;
+        width: 12px;
+        height: 12px;
+        border-radius: 6px;
+        background: #F1F3F4;
+      }
+    }
+    > menu {
+      position: absolute;
+      left: 340px;
+      bottom: 90px;
+      > button {
+        display: inline-block;
+        width: 48px;
+        height: 48px;
+        margin-right: 24px;
+        position: relative;
+        img {
+          width: 100%;
+          height: 100%;
+        }
+        .plus-one {
+          position: absolute;
+          top: 0;
+          right: 0;
+          transform: translate(50%, -50%);
+        }
+      }
+    }
+    .swiper-wrapper-mine {
+      position: absolute;
+      top: 50%;
+      right: 30px;
+      width: 720px;
+      height: 476px;
+      transform: translateY(-50%);
+      .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: -30px;
+          width: 30px;
+          background-image: url(../assets/images/arrow-left.png);
+          background-size: contain;
+          background-repeat: no-repeat;
+          background-position: center;
+          &::after {
+            content: '';
+          }
+        }
+        .swiper-button-next {
+          right: -30px;
+          width: 30px;
+          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 {
+    //   width: calc(100% - 1.67rem * 2 - 1.83rem * 2 - 1.67rem * 2);
+    //   height: 30rem;
+    //   position: absolute;
+    //   left: 50%;
+    //   top: 50%;
+    //   transform: translate(-50%, -70%);
+    //   .swiper-root {
+    //     width: 100%;
+    //     .swiper-wrapper {
+    //     }
+    //   }
+    // }
+    .swiper-wrapper-mine.image-wrap {
+      .swiper-root {
+        .swiper-wrapper {
+          > img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+          }
+        }
+      }
+    }
+  }
+}
+
+/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;
+}
+</style>

+ 0 - 0
src/views/temp


+ 3 - 0
vue.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  publicPath: "./"
+};