index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. <template>
  2. <div class="panocon">
  3. <template v-if="showInfo">
  4. <v-ifr
  5. v-if="activeItem.type == '4dkk'"
  6. @changeUrl="handleChange"
  7. @otherUrl="handleOther"
  8. :bgmUrl="bgmUrl"
  9. :somedatainfo="somedatainfo"
  10. :key="embeM || activeItem.sceneCode"
  11. :url="
  12. otherLink
  13. ? otherLink
  14. : `/embed.html?from=mingyuan&m=${
  15. embeM || activeItem.sceneCode
  16. }&lang=zh&scene-link=1&rnd=${rnd}`
  17. "
  18. />
  19. <!-- -->
  20. <div v-show="activeItem.type != '4dkk'" id="pano"></div>
  21. <div
  22. class="pano-logo"
  23. v-if="showInfo.isLogo && activeItem.type != '4dkk'"
  24. >
  25. <img
  26. :src="
  27. showInfo.logo ||
  28. require('@/assets/images/default/img_logoshow@2x.png')
  29. "
  30. alt=""
  31. />
  32. </div>
  33. <list
  34. v-if="canLoad && !isVR"
  35. @select="handleSelect"
  36. :firstScene="firstScene"
  37. :select="activeItem"
  38. :mapvisit="mapvisit"
  39. ></list>
  40. <ul class="aside" v-show="activeItem.type != '4dkk'">
  41. <li v-for="(item, i) in aside" :key="i">
  42. <span @click="handleItem(item)">
  43. <i class="iconfont" :class="item.icon"></i>
  44. </span>
  45. </li>
  46. </ul>
  47. <div
  48. class="oper-tips"
  49. :class="{ hidetips: !showTips }"
  50. v-if="localRemind"
  51. >
  52. <img
  53. :src="
  54. showInfo.appIcon ||
  55. require('@/assets/images/default/show/img_tipsmb_default.png')
  56. "
  57. alt=""
  58. />
  59. </div>
  60. <password
  61. :bg="showInfo.icon"
  62. :show="showPassword"
  63. @submit="handlePassword"
  64. @close="showPassword = false"
  65. />
  66. <popup :title="'简介'" :show="showIntro" @close="showIntro = false">
  67. <div slot="content" class="introcon">
  68. <span>{{ showInfo.description || "暂无简介" }}</span>
  69. </div>
  70. </popup>
  71. <imgview
  72. @close="showImage = false"
  73. v-if="showImage"
  74. :image="currentHotspot.image"
  75. />
  76. <preview
  77. :item="currentHotspot"
  78. :show="showPreview"
  79. @close="showPreview = false"
  80. />
  81. <popup
  82. :title="currentHotspot.hotspotTitle"
  83. :show="showTextarea"
  84. @close="showTextarea = false"
  85. >
  86. <div slot="content" class="introcon">
  87. <span>{{ currentHotspot.textarea }}</span>
  88. </div>
  89. </popup>
  90. <div v-if="audioUrl" class="audio-btn" @click="audioUrl = ''">
  91. <i class="iconfont icon-edit_soundview"></i>
  92. 停止播放
  93. <v-audio
  94. v-if="audioUrl"
  95. :vkey="audioUrl.id"
  96. class="vaduio"
  97. @audioEnded="handleEnded"
  98. :autoplay="true"
  99. :idleft="`_${$randomWord(true, 8, 8)}`"
  100. :idright="`_${$randomWord(true, 8, 8)}`"
  101. :myAudioUrl="audioUrl.audio.ossPath"
  102. ></v-audio>
  103. </div>
  104. </template>
  105. <template v-else>
  106. <div class="hasDel" v-if="loadFinish">
  107. <div>
  108. <img :src="$noresult" alt="" />
  109. <p>作品已被删除</p>
  110. </div>
  111. </div>
  112. </template>
  113. </div>
  114. </template>
  115. <script>
  116. import * as krfn from "@/core/index.js";
  117. import {
  118. getPanoInfo,
  119. checkPassword,
  120. checkWork,
  121. getSceneInfomation,
  122. } from "@/api";
  123. import password from "./popup/password";
  124. import preview from "./popup/preview";
  125. import { $smallWaiting } from "@/components/shared/loading";
  126. import imgview from "./popup/imgview";
  127. import vIfr from "./iframe";
  128. import Share from "@/utils/wxshare";
  129. import popup from "./popup/";
  130. import { mapGetters } from "vuex";
  131. import vAudio from "@/components/audio";
  132. import list from "./list";
  133. let __krfn = krfn.default;
  134. let bgmMap = {
  135. 欢快: "01.mp3",
  136. 空灵: "02.mp3",
  137. 节奏: "03.mp3",
  138. 怀旧: "04.mp3",
  139. 想念: "05.mp3",
  140. 复古: "06.mp3",
  141. 琴弦: "07.mp3",
  142. 愉快: "08.mp3",
  143. };
  144. export default {
  145. components: {
  146. list,
  147. password,
  148. popup,
  149. preview,
  150. imgview,
  151. vIfr,
  152. vAudio,
  153. },
  154. computed: {
  155. ...mapGetters({
  156. showInfo: "showInfo",
  157. }),
  158. },
  159. data() {
  160. return {
  161. mapvisit: 0,
  162. bgmUrl: "",
  163. somedatainfo: "",
  164. isVR: false,
  165. localRemind: false,
  166. showPreview: false,
  167. audioUrl: "",
  168. showTips: false,
  169. showImage: false,
  170. showAudio: false,
  171. canLoad: false,
  172. showPassword: false,
  173. showIntro: false,
  174. showTextarea: false,
  175. password: "",
  176. activeItem: "",
  177. firstScene: "",
  178. someData: "",
  179. currentHotspot: "",
  180. list: [],
  181. loadFinish: false,
  182. embeM: null,
  183. otherLink: null,
  184. rnd: null,
  185. aside: [
  186. {
  187. id: "about",
  188. icon: "icon-tool_about",
  189. },
  190. {
  191. id: "vr",
  192. icon: "icon-tool_vr",
  193. },
  194. ],
  195. };
  196. },
  197. methods: {
  198. handleOther(data) {
  199. this.otherLink = data;
  200. this.rnd = Math.random();
  201. },
  202. handleChange(data) {
  203. this.embeM = data;
  204. this.rnd = Math.random();
  205. },
  206. getSceneInfomation() {
  207. getSceneInfomation({ id: this.activeItem.sceneCode }, (data) => {
  208. this.mapvisit = data.data.mapVisi;
  209. this.somedatainfo = data.data;
  210. if (data.data.bgMusic) {
  211. if (bgmMap[data.data.bgMusic]) {
  212. this.bgmUrl =
  213. window.location.href.indexOf("www.4dkankan.com") > -1
  214. ? `https://4dkk.4dage.com/v3/audio/${bgmMap[data.data.bgMusic]}`
  215. : `https://4dkk.4dage.com/v3-test/audio/${
  216. bgmMap[data.data.bgMusic]
  217. }`;
  218. }
  219. if (data.data.bgMusic == "user") {
  220. this.bgmUrl = data.data.bgMusic
  221. ? `https://4dkk.4dage.com/images/images${data.data.num}/${data.data.bgMusicName}`
  222. : "";
  223. }
  224. }
  225. });
  226. },
  227. handleEnded() {
  228. this.audioUrl = "";
  229. },
  230. handleItem(data) {
  231. if (data.id == "about") {
  232. this.showIntro = true;
  233. }
  234. if (data.id == "vr") {
  235. this.$iosGrantedTips((data) => {
  236. if (data.code == 1) {
  237. var krpano = document.getElementById("krpanoSWFObject");
  238. var webvr = krpano.get("webvr");
  239. webvr.entervr();
  240. } else {
  241. this.$alert({
  242. content:
  243. "运动和方向访问失败,您需要完全关闭此应用,然后再次打开,并允许访问运动与方向",
  244. });
  245. }
  246. });
  247. }
  248. },
  249. handlePassword(data) {
  250. checkPassword(
  251. {
  252. password: data,
  253. },
  254. (res) => {
  255. if (res.code == 0) {
  256. this.showPassword = false;
  257. this.canLoad = true;
  258. }
  259. }
  260. );
  261. },
  262. startLoad() {
  263. this.canLoad = true;
  264. },
  265. handleSelect(data) {
  266. this.activeItem = data;
  267. },
  268. fixData() {
  269. let tmp = [];
  270. this.showInfo.scenes.forEach((item) => {
  271. this.showInfo.catalogs.forEach((sub) => {
  272. if (item.category == sub.id) {
  273. tmp.push(sub);
  274. }
  275. });
  276. });
  277. tmp = this.$unique(tmp);
  278. this.showInfo.catalogs = tmp;
  279. let rootmp = [];
  280. tmp.forEach((item) => {
  281. this.showInfo.catalogRoot.forEach((sub) => {
  282. sub.children = this.$unique(sub.children);
  283. if (sub.children.indexOf(item.id) > -1) {
  284. rootmp.push(sub);
  285. }
  286. });
  287. });
  288. rootmp = this.$unique(rootmp);
  289. let sortArr = this.showInfo.catalogRoot.map((item) => item.name);
  290. rootmp.sort((a, b) => {
  291. return sortArr.indexOf(a.name) - sortArr.indexOf(b.name);
  292. });
  293. this.showInfo.catalogRoot = rootmp.map((item) => {
  294. let temp = [];
  295. item.children = this.$unique(item.children);
  296. item.children.forEach((sub) => {
  297. tmp.forEach((jj) => {
  298. if (jj.id == sub) {
  299. temp.push(sub);
  300. }
  301. });
  302. });
  303. return {
  304. ...item,
  305. children: temp,
  306. };
  307. });
  308. this.showInfo.catalogs = tmp;
  309. let cid = "c_" + this.$randomWord(true, 8, 8);
  310. if (this.showInfo.catalogRoot.length <= 0) {
  311. this.showInfo.catalogRoot.push({
  312. id: "r_" + this.$randomWord(true, 8, 8),
  313. name: "全部场景",
  314. children: [cid],
  315. });
  316. }
  317. if (this.showInfo.catalogs.length <= 0) {
  318. this.showInfo.catalogs.push({
  319. id: cid,
  320. name: "默认二级分组",
  321. });
  322. }
  323. if (this.showInfo.firstScene) {
  324. this.showInfo.firstScene = this.showInfo.scenes.find(
  325. (item) => item.sceneCode == this.showInfo.firstScene.sceneCode
  326. );
  327. }
  328. this.$store.commit("SetShowInfo", this.showInfo);
  329. },
  330. getSceneInfo() {
  331. checkWork("", (data) => {
  332. if (data.data) {
  333. getPanoInfo("", (res) => {
  334. this.$store.commit("SetShowInfo", res);
  335. this.fixData();
  336. this.loadFinish = true;
  337. });
  338. } else {
  339. this.loadFinish = true;
  340. }
  341. });
  342. },
  343. },
  344. watch: {
  345. currentHotspot: {
  346. deep: true,
  347. handler: function (newVal) {
  348. if (newVal) {
  349. this.audioUrl = "";
  350. if (newVal.hotspotType == "link") {
  351. window.open(newVal.hyperlink, "_blank");
  352. return;
  353. }
  354. if (newVal.hotspotType == "scene") {
  355. this.activeItem = newVal.secne;
  356. return;
  357. }
  358. if (newVal.hotspotType == "image") {
  359. this.showImage = true;
  360. return;
  361. }
  362. if (newVal.hotspotType == "textarea") {
  363. this.showTextarea = true;
  364. return;
  365. }
  366. if (newVal.hotspotType == "audio") {
  367. this.audioUrl = newVal;
  368. return;
  369. }
  370. this.showPreview = true;
  371. }
  372. },
  373. },
  374. canLoad(newVal) {
  375. if (newVal) {
  376. setTimeout(() => {
  377. this.showTips = this.localRemind;
  378. setTimeout(() => {
  379. this.showTips = false;
  380. }, this.showInfo.remindTime * 1000);
  381. }, 2000);
  382. }
  383. },
  384. showInfo: {
  385. deep: true,
  386. immediate: true,
  387. handler: function (newVal) {
  388. if (newVal) {
  389. document.title = newVal.name || "无标题";
  390. let locoR = "localRemind" + newVal.id;
  391. if (!newVal.description) {
  392. this.aside.shift();
  393. }
  394. if (newVal.isRemind == 1) {
  395. this.localRemind = localStorage.getItem(locoR) == 1 ? false : true;
  396. localStorage.setItem(locoR, 1);
  397. } else {
  398. this.localRemind = true;
  399. localStorage.setItem(locoR, 0);
  400. }
  401. if (this.showInfo.firstScene) {
  402. if (this.showInfo.firstScene.type == "4dkk") {
  403. this.localRemind = false;
  404. }
  405. }
  406. newVal.password ? (this.showPassword = true) : this.startLoad();
  407. Share({
  408. title: newVal.name,
  409. link: newVal.share,
  410. imgUrl: newVal.icon,
  411. desc: newVal.description,
  412. });
  413. }
  414. },
  415. },
  416. activeItem: {
  417. handler(newVal) {
  418. this.$nextTick(() => {
  419. if (newVal.type == "4dkk") {
  420. this.embeM = null;
  421. this.otherLink = null;
  422. removepano("#pano");
  423. $("#pano").empty();
  424. this.getSceneInfomation();
  425. return;
  426. } else {
  427. this.bgmUrl = "";
  428. }
  429. removepano("#pano");
  430. $smallWaiting.show();
  431. $("#pano").empty();
  432. window.vrInitFn = () => {
  433. $smallWaiting.hide();
  434. var krpano = document.getElementById("krpanoSWFObject");
  435. __krfn.utils.initHotspot(krpano, newVal && newVal.someData, false);
  436. };
  437. window.vrViewFn = () => {
  438. try {
  439. let tmp = newVal.initVisual || {};
  440. var krpano = document.getElementById("krpanoSWFObject");
  441. krpano.set("view.vlookat", tmp.vlookat || 0);
  442. krpano.set("view.hlookat", tmp.hlookat || 0);
  443. krpano.set("autorotate.enabled", Boolean(this.showInfo.isAuto));
  444. } catch (error) {
  445. error;
  446. }
  447. };
  448. var settings = {
  449. "events[skin_events].onxmlcomplete": "js(window.vrViewFn());",
  450. "events[skin_events].onloadcomplete": "js(window.vrInitFn());",
  451. };
  452. if (newVal) {
  453. removepano("#pano");
  454. embedpano({
  455. // xml: "%HTMLPATH%/static/template/tour.xml",
  456. xml: `${this.$cdn}/720yun_fd_manage/${newVal.sceneCode}/vtour/tour.xml`,
  457. swf: "%HTMLPATH%/static/template/tour.swf",
  458. target: "pano",
  459. html5: "auto",
  460. mobilescale: 1,
  461. vars: settings,
  462. passQueryParameters: true,
  463. });
  464. }
  465. });
  466. },
  467. },
  468. },
  469. mounted() {
  470. window.__krfn = __krfn;
  471. this.$bus.on("clickHotspot", (data) => {
  472. let someData = this.activeItem.someData;
  473. if (typeof someData == "string") {
  474. someData = JSON.parse(this.activeItem.someData);
  475. }
  476. let idx = someData.hotspots.findIndex((item) => item.name == data);
  477. this.currentHotspot = someData.hotspots[idx];
  478. });
  479. this.$bus.on("isVR", (data) => {
  480. this.isVR = data;
  481. });
  482. this.getSceneInfo();
  483. },
  484. };
  485. </script>
  486. <style lang="less" scoped>
  487. .panocon {
  488. width: 100%;
  489. height: 100%;
  490. #pano {
  491. width: 100%;
  492. height: 100%;
  493. }
  494. .hasDel {
  495. background: #fff;
  496. width: 100%;
  497. height: 100%;
  498. position: relative;
  499. > div {
  500. position: absolute;
  501. top: 50%;
  502. left: 50%;
  503. transform: translate(-50%, -50%);
  504. color: #909090;
  505. text-align: center;
  506. font-size: 18px;
  507. > p {
  508. margin-top: 20px;
  509. }
  510. }
  511. }
  512. > iframe {
  513. width: 100%;
  514. height: 100%;
  515. }
  516. .audio-btn {
  517. display: inline-block;
  518. margin: 0 auto;
  519. height: 36px;
  520. line-height: 36px;
  521. min-width: 78px;
  522. cursor: pointer;
  523. text-overflow: ellipsis;
  524. text-align: center;
  525. overflow: hidden;
  526. white-space: nowrap;
  527. vertical-align: middle;
  528. display: flex;
  529. align-items: center;
  530. justify-content: center;
  531. position: fixed;
  532. left: calc(50% - 18px);
  533. transform: translateX(-50%);
  534. bottom: 44px;
  535. z-index: 9999;
  536. border-radius: 18px;
  537. background: rgba(0, 0, 0, 0.5);
  538. border: 1px solid rgba(255, 255, 255, 0.2);
  539. margin-left: 10px;
  540. padding: 0 10px;
  541. &.active {
  542. background: rgba(0, 0, 0, 0.3);
  543. border: 1px solid #0076f6;
  544. color: #0076f6;
  545. }
  546. .icon-edit_soundview {
  547. color: #0076f6;
  548. margin-right: 10px;
  549. }
  550. .vaduio {
  551. visibility: hidden;
  552. width: 0;
  553. }
  554. }
  555. .pano-logo {
  556. position: absolute;
  557. top: 10px;
  558. left: 10px;
  559. > img {
  560. max-width: 80px;
  561. max-height: 80px;
  562. pointer-events: none;
  563. }
  564. }
  565. .oper-tips {
  566. position: absolute;
  567. top: 40%;
  568. left: 50%;
  569. transform: translate(-50%, -50%);
  570. transition: display 0.3s ease;
  571. > img {
  572. max-width: 90%;
  573. }
  574. }
  575. .hidetips {
  576. display: none;
  577. }
  578. .aside {
  579. position: fixed;
  580. left: 15px;
  581. bottom: 34px;
  582. display: flex;
  583. > li {
  584. margin: 0 0 5px 5px;
  585. > span {
  586. width: 36px;
  587. height: 36px;
  588. display: inline-block;
  589. background: rgba(0, 0, 0, 0.5);
  590. border: 1px solid rgba(255, 255, 255, 0.2);
  591. opacity: 1;
  592. border-radius: 18px;
  593. position: relative;
  594. cursor: pointer;
  595. > i {
  596. position: absolute;
  597. top: 50%;
  598. left: 50%;
  599. transform: translate(-50%, -50%);
  600. }
  601. }
  602. }
  603. }
  604. .introcon {
  605. line-height: 20px;
  606. color: #909090;
  607. margin: 0 auto;
  608. width: 90%;
  609. word-break: break-all;
  610. max-height: 75vh;
  611. overflow-y: auto;
  612. -webkit-overflow-scrolling: touch;
  613. > span {
  614. display: inline-block;
  615. -webkit-overflow-scrolling: touch;
  616. text-align: justify;
  617. }
  618. }
  619. }
  620. </style>