SwkkView.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. <template>
  2. <div class="skww-view">
  3. <div
  4. class="swkk-wrap"
  5. />
  6. <menu>
  7. <button
  8. :class="{active: isAutoMoving}"
  9. @click="onClickAutoMoving"
  10. >
  11. <img
  12. v-show="!isAutoMoving"
  13. src="@/assets\images\swkk\zidongmanyou.png"
  14. alt=""
  15. draggable="false"
  16. >
  17. <img
  18. v-show="isAutoMoving"
  19. src="@/assets\images\swkk\zidongmanyou_1.png"
  20. alt=""
  21. draggable="false"
  22. >
  23. <div>自动漫游</div>
  24. </button>
  25. <button
  26. :class="{active: isShowTourGuide}"
  27. @click="onClickCjdl"
  28. >
  29. <img
  30. v-show="!isShowTourGuide"
  31. src="@/assets\images\swkk\changjingdaolan.png"
  32. alt=""
  33. draggable="false"
  34. >
  35. <img
  36. v-show="isShowTourGuide"
  37. src="@/assets\images\swkk\changjingdaolan_1.png"
  38. alt=""
  39. draggable="false"
  40. >
  41. <div>场景导览</div>
  42. </button>
  43. <button
  44. :class="{active: mode === 2}"
  45. @click="onClickQjmy"
  46. >
  47. <img
  48. v-show="mode !== 2"
  49. src="@/assets\images\swkk\quanjingmanyou.png"
  50. alt=""
  51. draggable="false"
  52. >
  53. <img
  54. v-show="mode === 2"
  55. src="@/assets\images\swkk\quanjingmanyou_1.png"
  56. alt=""
  57. draggable="false"
  58. >
  59. <div>全景漫游</div>
  60. </button>
  61. <button
  62. :class="{active: mode === 3}"
  63. @click="onClickMnmx"
  64. >
  65. <img
  66. v-show="mode !== 3"
  67. src="@/assets\images\swkk\minimoxing.png"
  68. alt=""
  69. draggable="false"
  70. >
  71. <img
  72. v-show="mode === 3"
  73. src="@/assets\images\swkk\minimoxing_1.png"
  74. alt=""
  75. draggable="false"
  76. >
  77. <div>迷你模型</div>
  78. </button>
  79. <button
  80. :class="{active: mode === 4}"
  81. @click="onClickDbfs"
  82. >
  83. <img
  84. v-show="mode !== 4"
  85. src="@/assets\images\swkk\dingbufushi.png"
  86. alt=""
  87. draggable="false"
  88. >
  89. <img
  90. v-show="mode === 4"
  91. src="@/assets\images\swkk\dingbufushi_1.png"
  92. alt=""
  93. draggable="false"
  94. >
  95. <div>顶部俯视</div>
  96. </button>
  97. </menu>
  98. <!-- 右上地图 -->
  99. <div
  100. v-show="!isLoading && mode === 2"
  101. class="mini-map"
  102. >
  103. <div
  104. class="radio-wrap"
  105. :class="{ active: floor === '1' }"
  106. @click="changeFloor('1')"
  107. >
  108. <div class="radio" />
  109. <div class="rowrr">
  110. 一层
  111. </div>
  112. </div>
  113. <div
  114. class="radio-wrap"
  115. :class="{ active: floor === '2' }"
  116. @click="changeFloor('2')"
  117. >
  118. <div class="radio" />
  119. <div class="rowrr">
  120. 二层
  121. </div>
  122. </div>
  123. </div>
  124. <!-- 导览栏 -->
  125. <div
  126. v-show="isShowTourGuide"
  127. class="tour-guide-wrap"
  128. :style="{
  129. zIndex: $globalConfig.zIndex.swkkGuideBar.self
  130. }"
  131. >
  132. <ul
  133. v-if="tourList.length"
  134. class="tour-guide"
  135. >
  136. <li
  137. v-for="(item, index) in tourList"
  138. :key="item.sid"
  139. ref="scene-item"
  140. :class="{active: curSceneIdx === index}"
  141. @click="changeScene(index)"
  142. >
  143. <img
  144. :src="item.enter.cover"
  145. alt=""
  146. draggable="false"
  147. >
  148. <div
  149. v-show="isAutoMoving && (curSceneIdx === index)"
  150. class="progress"
  151. :style="{
  152. width: autoMovingProgress + '%',
  153. }"
  154. />
  155. </li>
  156. </ul>
  157. </div>
  158. </div>
  159. </template>
  160. <script>
  161. export default {
  162. data() {
  163. //这里存放数据
  164. return {
  165. kankan: null,
  166. isLoading: true,
  167. floor: 0,
  168. isAutoMoving: false,
  169. isChangingAutoMovingStatus: false,
  170. autoMovingProgress: 0,
  171. isShowTourGuide: false,
  172. tourList: [],
  173. isChangingScene: false,
  174. curSceneIdx: null,
  175. mode: 2,
  176. hotspotRawData: null,
  177. hotspotDetail: null,
  178. // ------- ?
  179. title: true,
  180. partId: 0,
  181. frameId: null,
  182. progress: 0,
  183. disable: false,
  184. playing: false,
  185. }
  186. },
  187. computed: {
  188. ...globalMapState([
  189. 'isMuted',
  190. ])
  191. },
  192. watch: {
  193. isMuted: {
  194. handler(vNew) {
  195. if (!vNew) {
  196. this.stopAutoMoving()
  197. }
  198. }
  199. },
  200. isAutoMoving: {
  201. handler(vNew) {
  202. if (vNew) {
  203. this.isShowTourGuide = true
  204. } else {
  205. }
  206. }
  207. },
  208. isShowTourGuide: {
  209. handler(vNew) {
  210. if (vNew) {
  211. this.$msgCenter.publish('swkk-guide-bar-show')
  212. } else {
  213. this.$msgCenter.publish('swkk-guide-bar-hide')
  214. }
  215. }
  216. }
  217. },
  218. beforeMount() {
  219. this.$msgCenter.publish('show-loading')
  220. },
  221. mounted() {
  222. let floor = this.$route.query.floor
  223. this.floor = floor
  224. let sceneCode = ''
  225. if (floor === "1") sceneCode = process.env.VUE_APP_SCENE_CODE_FLOOR_1
  226. else if (floor === "2") sceneCode = process.env.VUE_APP_SCENE_CODE_FLOOR_2
  227. console.assert(sceneCode, 'no sceneCode!')
  228. // 不等一秒,就会因为use了小地图而卡死?
  229. setTimeout(() => {
  230. let kankan = new KanKan({
  231. dom: ".swkk-wrap",
  232. num: sceneCode,
  233. })
  234. kankan.use("MinMap", {
  235. theme: {
  236. camera_fillStyle: "#930909",
  237. },
  238. })
  239. kankan.use("TourPlayer").then((player) => {
  240. player.on("play", ({ partId, frameId }) => {
  241. this.isAutoMoving = true
  242. this.isChangingAutoMovingStatus = false
  243. this.mustMute()
  244. })
  245. player.on("pause", ({ partId, frameId }) => {
  246. this.isAutoMoving = false
  247. this.isChangingAutoMovingStatus = false
  248. this.cancelMustMute()
  249. })
  250. player.on("end", async () => {
  251. this.isAutoMoving = false
  252. this.isChangingAutoMovingStatus = false
  253. this.progress = 0
  254. this.frameId = null
  255. this.cancelMustMute()
  256. })
  257. player.on("progress", ({ partId, frameId, progress }) => {
  258. this.curSceneIdx = frameId
  259. this.$refs['scene-item'][this.curSceneIdx].scrollIntoView()
  260. this.autoMovingProgress = Number(progress * 100).toFixed(5)
  261. })
  262. })
  263. // // 有关球幕视频控制背景音乐
  264. // kankan.Scene.on("panorama.videorenderer.startvideo", () => {
  265. // // 点击热点的时候当前背景音乐的播放状态
  266. // let dom = document.querySelector("#bacMusic")
  267. // window.bacMusic = !dom.paused
  268. // setTimeout(() => {
  269. // this.$refs.RbottomRef.opMusic(false)
  270. // }, 200)
  271. // // 暂停背景音乐
  272. // })
  273. // kankan.Scene.on("panorama.videorenderer.resumerender", () => {
  274. // // 点击热点的时候当前背景音乐的播放状态
  275. // let dom = document.querySelector("#bacMusic")
  276. // window.bacMusic = !dom.paused
  277. // setTimeout(() => {
  278. // this.$refs.RbottomRef.opMusic(false)
  279. // }, 200)
  280. // // 暂停背景音乐
  281. // })
  282. // kankan.Scene.on("panorama.videorenderer.suspendrender", () => {
  283. // if (window.bacMusic) {
  284. // setTimeout(() => {
  285. // this.$refs.RbottomRef.opMusic(true)
  286. // }, 100)
  287. // }
  288. // // 恢复背景音乐
  289. // })
  290. // 导览数据
  291. kankan.TourManager.on("loaded", (tours) => {
  292. try {
  293. this.tourList = tours[0].list
  294. } catch (e) {
  295. console.error('没拿到导览数据:', e)
  296. this.tourList = []
  297. }
  298. this.$msgCenter.publish('hide-loading')
  299. })
  300. // 全部热点数据
  301. kankan.store.on("tags", (tags) => {
  302. this.baseHotData = tags.tags
  303. })
  304. // 热点
  305. kankan
  306. .use("TagView", {
  307. render(data) {
  308. let ifNeedShow = false
  309. // data.title如果没有“&”或者是“a&b&show”这样子,就要显示。
  310. let arrTitle = data.title.split("&")
  311. if (arrTitle[2] === 'show' || !data.title.includes("&")) {
  312. ifNeedShow = true
  313. }
  314. let title = data.title.split("&")[0]
  315. return `
  316. <span class="tag-icon animate" title=${title} style="${ifNeedShow ? "" : "display: none;"}; background-image: url({{icon}})"></span>
  317. <div class="tag-body"></div>
  318. `
  319. },
  320. })
  321. .then((TagView) => {
  322. // 监听手动点击事件
  323. TagView.on("click", (e) => {
  324. // // 点击热点的时候当前背景音乐的播放状态
  325. // let dom = document.querySelector("#bacMusic")
  326. // window.bacMusic = !dom.paused
  327. // setTimeout(() => {
  328. // this.$refs.RbottomRef.opMusic(false)
  329. // }, 200)
  330. if (e.data.title.split("&")[1]) { // 如果是多个热点合并
  331. let hotspotList = []
  332. this.hotspotRawData.forEach((item) => {
  333. if (item.title.split("&")[1] === e.data.title.split("&")[1]) {
  334. hotspotList.push(item)
  335. }
  336. })
  337. let obj = {
  338. image: [],
  339. audio: [],
  340. link: [],
  341. video: [],
  342. }
  343. hotspotList.forEach((hotspot) => {
  344. obj[hotspot.type].push(hotspot)
  345. })
  346. this.hotspotDetail = obj
  347. } else { // 单个热点
  348. this.hotspotDetail = { [e.data.type]: [e.data] }
  349. }
  350. // 聚焦当前点击的热点
  351. TagView.focus(e.data.sid)
  352. })
  353. })
  354. kankan.render()
  355. kankan.Scene.on("loaded", () => {
  356. console.log('loaded!')
  357. this.isLoading = false
  358. //设置地面logo
  359. kankan.Scene.setFloorLogo({
  360. url: "./img/diBiao.png",
  361. size: 40,
  362. })
  363. })
  364. // 监听看看的模式
  365. kankan.Camera.on("mode.beforeChange", ({ toMode }) => {
  366. this.mode = {
  367. floorplan: 4,
  368. dollhouse: 3,
  369. panorama: 2,
  370. }[toMode]
  371. })
  372. this.kankan = kankan
  373. }, 1000)
  374. },
  375. beforeDestroy() {
  376. this.stopAutoMoving()
  377. },
  378. methods: {
  379. ...globalMapMutations([
  380. 'mustMute',
  381. 'cancelMustMute',
  382. ]),
  383. // 切换楼层
  384. changeFloor(val) {
  385. this.$router.replace({
  386. name: 'SwkkView',
  387. query: { floor: val }
  388. })
  389. setTimeout(() => {
  390. location.reload(true)
  391. }, 200)
  392. },
  393. onClickAutoMoving() {
  394. if (this.isAutoMoving) {
  395. this.stopAutoMoving()
  396. } else {
  397. this.startAutoMoving()
  398. }
  399. },
  400. async startAutoMoving() {
  401. if (this.isChangingAutoMovingStatus || this.isAutoMoving) {
  402. return
  403. }
  404. this.isChangingAutoMovingStatus = true
  405. let player = await this.kankan.TourManager.player
  406. player.play()
  407. },
  408. async stopAutoMoving() {
  409. if (this.isChangingAutoMovingStatus || !this.isAutoMoving) {
  410. return
  411. }
  412. this.isChangingAutoMovingStatus = true
  413. let player = await this.kankan.TourManager.player
  414. player.pause()
  415. },
  416. onClickCjdl() {
  417. this.isShowTourGuide = !this.isShowTourGuide
  418. },
  419. onClickQjmy() {
  420. this.kankan.Camera.panorama()
  421. },
  422. onClickMnmx() {
  423. this.stopAutoMoving()
  424. this.kankan.Camera.dollhouse()
  425. },
  426. onClickDbfs() {
  427. this.stopAutoMoving()
  428. this.kankan.Camera.floorplan()
  429. },
  430. async changeScene(index) {
  431. if (this.isChangingScene) {
  432. return
  433. }
  434. this.stopAutoMoving()
  435. this.isChangingScene = true
  436. this.curSceneIdx = index
  437. let player = await this.kankan.TourManager.player
  438. player.pause()
  439. await player.selectFrame(index)
  440. this.isChangingScene = false
  441. },
  442. },
  443. }
  444. </script>
  445. <style lang="less" scoped>
  446. .skww-view {
  447. position: relative;
  448. width: 100%;
  449. height: 100%;
  450. .swkk-wrap {
  451. position: absolute;
  452. top: 0;
  453. left: 0;
  454. width: 100%;
  455. height: 100%;
  456. }
  457. > menu {
  458. position: absolute;
  459. z-index: 1;
  460. top: 2rem;
  461. left: 1.75rem;
  462. display: flex;
  463. flex-direction: column;
  464. align-items: center;
  465. gap: 0.83rem;
  466. > button {
  467. > img {
  468. width: 5rem;
  469. height: 5rem;
  470. }
  471. > div {
  472. color: #fff;
  473. text-shadow: 0px 0px 0.2rem rgba(255,255,255,0.6);
  474. margin-top: 0.17rem;
  475. font-size: 1.17rem;
  476. }
  477. &.active {
  478. > div {
  479. color: #930909;
  480. text-shadow: 0px 0px 0.2rem rgba(255,255,255,0.6);
  481. }
  482. }
  483. }
  484. }
  485. /deep/[xui_min_map] {
  486. top: 7rem;
  487. right: 1.67rem;
  488. width: 18rem;
  489. height: 18rem;
  490. border: 0.08rem solid #D8B275;
  491. background-color: rgba(81, 32, 32, 0.4);
  492. border-radius: 0 0 0.42rem 0.42rem;
  493. }
  494. .mini-map {
  495. position: absolute;
  496. z-index: 1;
  497. right: 1.67rem;
  498. top: 2.5rem;
  499. border: 0.08rem solid #d8b275;
  500. border-radius: 0.42rem 0.42rem 0 0;
  501. color: #fff;
  502. width: 18rem;
  503. height: 4.6rem;
  504. background-color: #930909;
  505. display: flex;
  506. justify-content: space-evenly;
  507. .radio-wrap {
  508. display: flex;
  509. justify-content: center;
  510. align-items: center;
  511. font-size: 1.67rem;
  512. .radio {
  513. margin-right: 0.5rem;
  514. width: 2.2rem;
  515. height: 2.2rem;
  516. border-radius: 50%;
  517. border: 0.08rem solid #fff;
  518. position: relative;
  519. }
  520. .rowrr {
  521. }
  522. }
  523. .active {
  524. color: #d8b275;
  525. pointer-events: none;
  526. .radio {
  527. &::after {
  528. content: "";
  529. position: absolute;
  530. top: 50%;
  531. left: 50%;
  532. transform: translate(-50%, -50%);
  533. border-radius: 50%;
  534. width: 1rem;
  535. height: 1rem;
  536. background-color: #d8b275;
  537. }
  538. }
  539. }
  540. }
  541. .tour-guide-wrap {
  542. position: absolute;
  543. left: 0;
  544. bottom: 0;
  545. width: 100%;
  546. height: 13.75rem;
  547. background: rgba(216,178,117,0.6);
  548. padding: 1.17rem 1.17rem 1.92rem 1.17rem;
  549. .tour-guide {
  550. display: flex;
  551. align-items: center;
  552. gap: 0.83rem;
  553. overflow: auto;
  554. width: 100%;
  555. height: 100%;
  556. > li {
  557. flex: 0 0 auto;
  558. width: 12.5rem;
  559. height: 7.5rem;
  560. position: relative;
  561. > img {
  562. background: #D26868;
  563. width: 100%;
  564. height: 100%;
  565. object-fit: cover;
  566. }
  567. > .progress {
  568. position: absolute;
  569. left: 0;
  570. bottom: 0;
  571. height: 0.5rem;
  572. background-color: #930909;
  573. }
  574. &.active {
  575. border: 0.33rem solid #930909;
  576. }
  577. }
  578. }
  579. }
  580. }
  581. </style>