HomeWeb.vue 16 KB

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