index.vue 14 KB

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