HomeWeb.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. <template>
  2. <div
  3. ref="comp-root"
  4. class="hotspot-home"
  5. >
  6. <audio
  7. ref="bg-audio"
  8. class="bg-audio"
  9. :src="bgAudioUrl"
  10. />
  11. <button
  12. class="close"
  13. @click="onClickClose"
  14. >
  15. <img
  16. src="@/assets/images/close.png"
  17. alt="关闭"
  18. draggable="false"
  19. >
  20. </button>
  21. <div
  22. class="bg-wrapper"
  23. :style="{
  24. backgroundImage: `url(${bgImg})`,
  25. }"
  26. >
  27. <h1
  28. :title="hotspotLocalInfo.title"
  29. :style="{
  30. backgroundImage: `url(${titleBottomLine})`,
  31. }"
  32. v-html="hotspotLocalInfo.title"
  33. />
  34. <div
  35. class="textInfo"
  36. >
  37. <ul>
  38. <li v-show="hotspotLocalInfo.age">
  39. <span class="key">时代:</span>
  40. <span class="value">{{ hotspotLocalInfo.age }}</span>
  41. </li>
  42. <li v-show="hotspotLocalInfo.position">
  43. <span class="key">出土地:</span>
  44. <span class="value">{{ hotspotLocalInfo.position }}</span>
  45. </li>
  46. <li v-show="hotspotLocalInfo.size">
  47. <span class="key">尺寸:</span>
  48. <span class="value">{{ hotspotLocalInfo.size }}</span>
  49. </li>
  50. <li v-show="hotspotLocalInfo.desc">
  51. <span class="key">介绍:</span>
  52. <span
  53. class="value"
  54. v-html="hotspotLocalInfo.desc"
  55. />
  56. </li>
  57. </ul>
  58. </div>
  59. <menu>
  60. <button
  61. v-if="bgAudioUrl"
  62. @click="isBgAudioMuted = !isBgAudioMuted"
  63. >
  64. <img
  65. v-show="!isBgAudioMuted"
  66. class="bg-audio-control"
  67. src="@/assets/images/bg-audio.png"
  68. alt=""
  69. draggable="false"
  70. >
  71. <img
  72. v-show="isBgAudioMuted"
  73. class="bg-audio-control"
  74. src="@/assets/images/bg-audio-muted.png"
  75. alt=""
  76. draggable="false"
  77. >
  78. </button>
  79. <!-- <button @click="onClickLike">
  80. <img
  81. class="like"
  82. src="@/assets/images/like.png"
  83. alt=""
  84. draggable="false"
  85. >
  86. <transition name="bubble">
  87. <div
  88. v-if="isShowPlusOne"
  89. class="plus-one"
  90. >
  91. +1
  92. </div>
  93. </transition>
  94. </button> -->
  95. <!-- <button @click="onClickShare">
  96. <img
  97. class="share"
  98. src="@/assets/images/share.png"
  99. alt=""
  100. draggable="false"
  101. >
  102. </button> -->
  103. </menu>
  104. <div class="type-tabbar">
  105. <button
  106. v-if="hasModels"
  107. :class="{inactive: activeType !== 0}"
  108. @click="activeType = 0"
  109. >
  110. <img
  111. :src="require(`@/assets/images/hotspot-model-pc-${activeType === 0 ? 'active' : 'normal'}.png`)"
  112. alt=""
  113. draggable="false"
  114. >
  115. </button>
  116. <button
  117. v-if="hasImages"
  118. :class="{inactive: activeType !== 1}"
  119. @click="activeType = 1"
  120. >
  121. <img
  122. :src="require(`@/assets/images/hotspot-image-pc-${activeType === 1 ? 'active' : 'normal'}.png`)"
  123. alt=""
  124. draggable="false"
  125. >
  126. </button>
  127. </div>
  128. <!-- <div
  129. v-if="hasVideos"
  130. class="swiper-wrapper-mine video-wrap"
  131. >
  132. <div
  133. class="swiper-root"
  134. >
  135. <div
  136. class="swiper-wrapper"
  137. >
  138. <div
  139. v-for="(item, index) in hotspotData.video"
  140. :key="index"
  141. class="swiper-slide"
  142. >
  143. <video
  144. ref="video"
  145. :src="item.url"
  146. controls
  147. controlslist="nodownload"
  148. disablePictureInPicture
  149. />
  150. </div>
  151. </div>
  152. <div class="swiper-pagination" />
  153. <div class="swiper-button-prev" />
  154. <div class="swiper-button-next" />
  155. </div>
  156. </div> -->
  157. <div
  158. v-if="hasModels && activeType === 0"
  159. class="swiper-wrapper-mine model-wrap"
  160. >
  161. <div
  162. class="swiper-root"
  163. >
  164. <div
  165. class="swiper-wrapper"
  166. >
  167. <iframe
  168. v-for="(item, index) in hotspotData.model"
  169. :key="index"
  170. :src="$env.VUE_APP_CLI_MODE === 'local' ? `${$env.VUE_APP_RELIC_MODEL_PATH}?m=${item.split('m=')[1]}` : item"
  171. frameborder="0"
  172. class="swiper-slide"
  173. />
  174. </div>
  175. <div class="swiper-pagination" />
  176. <div class="swiper-button-prev" />
  177. <div class="swiper-button-next" />
  178. </div>
  179. </div>
  180. <!-- <div
  181. v-if="hasAudios"
  182. class="swiper-wrapper-mine audio-wrap"
  183. >
  184. <div
  185. class="swiper-root"
  186. >
  187. <div
  188. class="swiper-wrapper"
  189. >
  190. <div
  191. v-for="(item, index) in hotspotData.audio"
  192. :key="index"
  193. class="swiper-slide"
  194. >
  195. <audio
  196. ref="audio"
  197. :src="item.url"
  198. controls
  199. controlslist="nodownload"
  200. disablePictureInPicture
  201. />
  202. </div>
  203. </div>
  204. <div class="swiper-pagination" />
  205. <div class="swiper-button-prev" />
  206. <div class="swiper-button-next" />
  207. </div>
  208. </div> -->
  209. <div
  210. v-if="hasImages && activeType === 1"
  211. class="swiper-wrapper-mine image-wrap"
  212. >
  213. <div
  214. class="swiper-root"
  215. >
  216. <div
  217. v-viewer="{
  218. button: true,
  219. navbar: false,
  220. title: false,
  221. toolbar: false,
  222. tooltip: false,
  223. movable: true,
  224. zoomable: true,
  225. rotatable: true,
  226. scalable: true,
  227. transition: false,
  228. fullscreen: false,
  229. keyboard: true,
  230. loop: false,
  231. }"
  232. class="swiper-wrapper"
  233. >
  234. <img
  235. v-for="(item, index) in hotspotData.images"
  236. :key="index"
  237. v-lazy="item"
  238. class="swiper-slide"
  239. alt=""
  240. draggable="false"
  241. >
  242. </div>
  243. <div class="swiper-pagination">
  244. <!-- <span
  245. class="cur"
  246. >
  247. {{ currentSlideIdx + 1 }}
  248. </span>
  249. /
  250. <span>
  251. {{ hotspotData.Images ? hotspotData.images.length : '' }}
  252. </span> -->
  253. </div>
  254. <div class="swiper-button-prev" />
  255. <div class="swiper-button-next" />
  256. </div>
  257. </div>
  258. <div
  259. v-if="isShowShare"
  260. v-click-outside.click="closeCode2d"
  261. class="share-wrap"
  262. >
  263. <img
  264. src="@/assets/images/code2d.png"
  265. alt=""
  266. class="code"
  267. draggable="false"
  268. >
  269. <img
  270. src="@/assets/images/share-tip.png"
  271. alt=""
  272. class="tip"
  273. draggable="false"
  274. >
  275. </div>
  276. </div>
  277. </div>
  278. </template>
  279. <script>
  280. import Swiper from 'swiper/swiper-bundle.esm.js'
  281. import 'swiper/swiper-bundle.css'
  282. import bgImg from "@/assets/images/bg.png"
  283. import titleBottomLine from "@/assets/images/title-bottom-line.png"
  284. import { deepProcess } from "@/utils/other.js"
  285. // import browser from "@/utils/browser";
  286. import hotspotLocalData from "@/assets/data/hotspotData.js"
  287. export default {
  288. data() {
  289. return {
  290. hotspotData: {}, // 热点数据
  291. isBgAudioMuted: true,
  292. hasImages: false,
  293. hasModels: false,
  294. // hasVideos: false,
  295. // hasAudios: false,
  296. activeType: null, // 0: 模型, 1: 图片
  297. currentSlideIdx: 0,
  298. bgImg,
  299. titleBottomLine,
  300. isShowPlusOne: false,
  301. isShowShare: false,
  302. }
  303. },
  304. computed: {
  305. hotspotLocalInfo() {
  306. const ret = hotspotLocalData.find((item) => {
  307. return item.id === this.$route.query.m
  308. })
  309. return ret
  310. },
  311. bgAudioUrl() {
  312. return this.hotspotLocalInfo?.audio ? require(`@/assets/audios/${this.hotspotLocalInfo.audio}`) : ''
  313. }
  314. },
  315. watch: {
  316. isBgAudioMuted: {
  317. handler(vNew) {
  318. if (vNew) {
  319. this.$refs['bg-audio'].pause() // or toggle静音?
  320. } else {
  321. this.$refs['bg-audio'].play() // or toggle静音?
  322. }
  323. }
  324. },
  325. activeType: {
  326. handler(vNew) {
  327. this.currentSlideIdx = 0
  328. // init swiper
  329. this.$nextTick(() => {
  330. const that = this
  331. new Swiper('.swiper-root', {
  332. pagination: {
  333. el: '.swiper-pagination',
  334. },
  335. navigation: {
  336. nextEl: '.swiper-button-next',
  337. prevEl: '.swiper-button-prev',
  338. },
  339. // on: {
  340. // // 自动播放
  341. // afterInit: function (e) {
  342. // if (that.hasVideos) {
  343. // that.$nextTick(() => {
  344. // that.$refs.video[0].play()
  345. // })
  346. // }
  347. // if (that.hasAudios) {
  348. // that.$nextTick(() => {
  349. // that.$refs.audio[0].play()
  350. // })
  351. // }
  352. // },
  353. // slideChange: function(e) {
  354. // that.currentSlideIdx = e.activeIndex
  355. // // 自动播放
  356. // if (that.hasVideos) {
  357. // for (let index = 0; index < that.$refs.video.length; index++) {
  358. // if (index !== that.currentSlideIdx) {
  359. // that.$refs.video[index].pause()
  360. // } else {
  361. // that.$refs.video[index].play()
  362. // }
  363. // }
  364. // }
  365. // if (that.hasAudios) {
  366. // for (let index = 0; index < that.$refs.audio.length; index++) {
  367. // if (index !== that.currentSlideIdx) {
  368. // that.$refs.audio[index].pause()
  369. // } else {
  370. // that.$refs.audio[index].play()
  371. // }
  372. // }
  373. // }
  374. // }
  375. // }
  376. })
  377. })
  378. }
  379. }
  380. },
  381. async mounted() {
  382. setTimeout(() => {
  383. if (this.bgAudioUrl) {
  384. this.isBgAudioMuted = false
  385. }
  386. }, 2000)
  387. await this.getData()
  388. // 热点详情弹窗尺寸适应窗口
  389. if (window.innerWidth < 1350 || window.innerHeight < 810) {
  390. const realWHRatio = window.innerWidth / window.innerHeight
  391. if (realWHRatio > 1350 / 810) {
  392. const scaleRate = window.innerHeight / 810
  393. this.$refs['comp-root'].style.transform = `translate(-50%, -50%) scale(${scaleRate})`
  394. } else {
  395. const scaleRate = window.innerWidth / 1350
  396. this.$refs['comp-root'].style.transform = `translate(-50%, -50%) scale(${scaleRate})`
  397. }
  398. }
  399. },
  400. methods: {
  401. changeSubStr(str) {
  402. return str.replace('https://super.4dage.com/', process.env.VUE_APP_G_PREFIX)
  403. },
  404. async getData() {
  405. let url = `${process.env.VUE_APP_G_PREFIX}data/${this.$route.query.id}/hot/js/data.js?time=${Math.random()}`
  406. let result = (await this.$http.get(url)).data
  407. // 打印所有热点中的感兴趣的字段
  408. // console.log(result)
  409. // for (const key in result) {
  410. // if (Object.hasOwnProperty.call(result, key)) {
  411. // const element = result[key]
  412. // console.log(element.sid, element.title)
  413. // }
  414. // }
  415. deepProcess(result, this.changeSubStr)
  416. this.hotspotData = result[this.$route.query.m]
  417. if (!this.hotspotData) {
  418. return alert("热点解析错误")
  419. }
  420. console.log('热点数据:', this.hotspotData)
  421. // this.bgAudioUrl = this.hotspotData.backgroundMusic
  422. if (this.hotspotData.images && this.hotspotData.images.length) {
  423. this.hasImages = true
  424. }
  425. if (this.hotspotData.model && this.hotspotData.model.length) {
  426. this.hasModels = true
  427. }
  428. // if (this.hotspotData.video && this.hotspotData.video.length) {
  429. // this.hasVideos = true
  430. // }
  431. // else if (this.hotspotData.backgroundMusic) {
  432. // this.hasAudios = true
  433. // this.hotspotData.audio = [{ url: this.hotspotData.backgroundMusic }]
  434. // }
  435. if (this.hasModels) {
  436. this.activeType = 0
  437. } else if (this.hasImages) {
  438. this.activeType = 1
  439. }
  440. },
  441. onClickClose() {
  442. window.parent.document.getElementById('closepop').click()
  443. },
  444. // onClickLike() {
  445. // const res = globalApi.like()
  446. // if (res && res.then) {
  447. // res.then(() => {
  448. // this.isShowPlusOne = true
  449. // setTimeout(() => {
  450. // this.isShowPlusOne = false
  451. // }, 1000)
  452. // })
  453. // }
  454. // },
  455. onClickShare() {
  456. setTimeout(() => {
  457. this.isShowShare = true
  458. }, 200)
  459. },
  460. closeCode2d() {
  461. if (this.isShowShare) {
  462. this.isShowShare = false
  463. }
  464. }
  465. }
  466. }
  467. </script>
  468. <style lang="less" scoped>
  469. .hotspot-home {
  470. position: absolute;
  471. left: 50%;
  472. top: 50%;
  473. width: 1350px;
  474. height: 810px;
  475. padding: 0 70px 0 0;
  476. color: #F1F3F4;
  477. transform: translate(-50%, -50%);
  478. > .bg-audio {
  479. display: none;
  480. }
  481. > button.close {
  482. position: absolute;
  483. top: 10px;
  484. right: 0px;
  485. width: 58px;
  486. height: 58px;
  487. > img {
  488. width: 100%;
  489. height: 100%;
  490. }
  491. }
  492. > .bg-wrapper {
  493. width: 100%;
  494. height: 100%;
  495. position: relative;
  496. background-size: contain;
  497. background-repeat: no-repeat;
  498. background-position: center center;
  499. > h1 {
  500. text-align: center;
  501. position: absolute;
  502. top: 150px;
  503. left: 44px;
  504. max-width: 418px;
  505. font-size: 38px;
  506. font-family: DFLiShuW7;
  507. letter-spacing: 5px;
  508. padding-left: 10px;
  509. padding-right: 10px;
  510. padding-bottom: 24px;
  511. background-size: contain;
  512. background-repeat: no-repeat;
  513. background-position: center bottom;
  514. }
  515. > .textInfo {
  516. position: absolute;
  517. top: 347px;
  518. left: 55px;
  519. width: 400px;
  520. font-size: 16px;
  521. line-height: 26px;
  522. font-family: Adobe Heiti Std;
  523. overflow: auto;
  524. height: 300px;
  525. padding-right: 10px;
  526. > ul {
  527. > li {
  528. display: block;
  529. margin-bottom: 0.5em;
  530. margin-left: 31px;
  531. position: relative;
  532. white-space: pre-wrap;
  533. &::before {
  534. position: absolute;
  535. left: -24px;
  536. top: 6px;
  537. content: '';
  538. background-color: #F1F3F4;
  539. display: inline-block;
  540. width: 12px;
  541. height: 12px;
  542. border-radius: 6px;
  543. }
  544. }
  545. }
  546. }
  547. > menu {
  548. position: absolute;
  549. right: 817px;
  550. bottom: 90px;
  551. > button {
  552. display: inline-block;
  553. width: 48px;
  554. height: 48px;
  555. margin-left: 24px;
  556. position: relative;
  557. img {
  558. width: 100%;
  559. height: 100%;
  560. }
  561. // .plus-one {
  562. // position: absolute;
  563. // top: 0;
  564. // right: 0;
  565. // transform: translate(50%, -50%);
  566. // }
  567. }
  568. }
  569. > .type-tabbar {
  570. position: absolute;
  571. top: 10%;
  572. right: 580px;
  573. display: flex;
  574. justify-content: space-between;
  575. align-items: center;
  576. > button {
  577. width: 80px;
  578. margin-left: 10px;
  579. &:first-of-type.inactive {
  580. width: 50px;
  581. }
  582. &:last-of-type.inactive {
  583. width: 50px;
  584. margin-right: 5px;
  585. margin-left: 30px;
  586. }
  587. > img {
  588. width: 100%;
  589. height: 100%;
  590. }
  591. }
  592. }
  593. .swiper-wrapper-mine {
  594. position: absolute;
  595. top: 50%;
  596. right: 30px;
  597. width: 720px;
  598. height: 476px;
  599. transform: translateY(-50%);
  600. .swiper-root {
  601. overflow: hidden;
  602. height: 100%;
  603. width: 100%;
  604. .swiper-wrapper {
  605. }
  606. .swiper-pagination {
  607. position: absolute;
  608. top: 100%;
  609. left: 50%;
  610. transform: translateX(-50%);
  611. font-size: 1.33rem;
  612. font-family: Inter-Regular, Inter;
  613. .cur {
  614. }
  615. }
  616. .swiper-button-prev {
  617. left: -30px;
  618. width: 30px;
  619. background-image: url(../assets/images/arrow-left.png);
  620. background-size: contain;
  621. background-repeat: no-repeat;
  622. background-position: center;
  623. &::after {
  624. content: '';
  625. }
  626. }
  627. .swiper-button-next {
  628. right: -30px;
  629. width: 30px;
  630. background-image: url(../assets/images/arrow-right.png);
  631. background-size: contain;
  632. background-repeat: no-repeat;
  633. background-position: center;
  634. &::after {
  635. content: '';
  636. }
  637. }
  638. }
  639. }
  640. .swiper-wrapper-mine.video-wrap {
  641. .swiper-root {
  642. .swiper-wrapper {
  643. .swiper-slide {
  644. > video {
  645. width: 100%;
  646. height: 100%;
  647. background: #000;
  648. }
  649. }
  650. }
  651. }
  652. }
  653. .swiper-wrapper-mine.model-wrap {
  654. .swiper-root {
  655. .swiper-wrapper {
  656. }
  657. }
  658. }
  659. .swiper-wrapper-mine.audio-wrap {
  660. .swiper-root {
  661. .swiper-wrapper {
  662. .swiper-slide {
  663. > audio {
  664. position: absolute;
  665. top: 50%;
  666. width: 100%;
  667. transform: translateY(-50%);
  668. }
  669. }
  670. }
  671. }
  672. }
  673. .swiper-wrapper-mine.image-wrap {
  674. .swiper-root {
  675. .swiper-wrapper {
  676. > img {
  677. width: 100%;
  678. height: 100%;
  679. object-fit: contain;
  680. }
  681. }
  682. }
  683. }
  684. .share-wrap {
  685. position: absolute;
  686. top: 50%;
  687. transform: translateY(-50%);
  688. right: 244px;
  689. > img.code {
  690. width: 300px;
  691. height: 300px;
  692. }
  693. > img.tip {
  694. position: absolute;
  695. left: 50%;
  696. top: calc(100% + 10px);
  697. transform: translateX(-50%);
  698. width: 150px;
  699. }
  700. }
  701. }
  702. }
  703. /deep/.swiper-pagination-bullet-active {
  704. background: #a10e0c;
  705. }
  706. // .bubble-enter {
  707. // opacity: 0;
  708. // top: 1rem !important;
  709. // }
  710. // .bubble-enter-to {
  711. // opacity: 1;
  712. // top: 0 !important;
  713. // }
  714. // .bubble-enter-active {
  715. // transition: all 0.5s;
  716. // }
  717. // .bubble-leave {
  718. // opacity: 1;
  719. // top: 0 !important;
  720. // }
  721. // .bubble-leave-to {
  722. // opacity: 0;
  723. // top: -1rem !important;
  724. // }
  725. // .bubble-leave-active {
  726. // transition: all 0.5s;
  727. // }
  728. </style>