HotSpotList.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. <template>
  2. <div class="hot-spot-list" app-border dir-left>
  3. <div class="title">
  4. {{$i18n.t('hotspot.add_hotspot')}}
  5. <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="$i18n.t('hotspot.hotspot_tips')" />
  6. </div>
  7. <template v-if="currentScene.type !== '4dkk'">
  8. <ul class="hotspot-type-list">
  9. <li
  10. class="hotspot-type-item"
  11. v-for="(item, index) in hotspotTypeList"
  12. :key="index"
  13. @click="open({
  14. isAdd: true,
  15. hotspotType: item.id,
  16. idxInSystemIconList: item.idxInSystemIconList
  17. })"
  18. >
  19. <img class="icon" :src="item.icon" alt="" draggable="false">
  20. <div class="type-name">{{item.name}}</div>
  21. <img
  22. v-if="item.isExperience"
  23. class="exp-tag"
  24. src="@/assets/img/experience.png"
  25. alt=""
  26. draggable="false"
  27. >
  28. </li>
  29. </ul>
  30. <div class="total-count">{{$i18n.t('hotspot.current_hotspots')}}
  31. <span class="number">({{ someData.hotspots.length }})</span>
  32. </div>
  33. <div class="hots">
  34. <ul v-if="someData.hotspots.length > 0">
  35. <li v-for="(item, key) in someData.hotspots" :key="key" @click="open(item)">
  36. <img class="hot-spot-thumb" :src="item.img" alt="">
  37. <span class="hot-spot-title" v-title="item.hotspotTitle">{{ item.hotspotTitle }}</span>
  38. <i
  39. class="iconfont icon-editor_list_delete icon-delete"
  40. v-tooltip="$i18n.t('hotspot.delete')"
  41. @click.stop="deleIndex = key"
  42. />
  43. <div class="deletion-confirm-wrap">
  44. <div class="deletion-confirm" :class="deleIndex == key ? 'show' : 'hide'" v-clickoutside="clickoutside"
  45. @click.stop="deleteHot(item)">
  46. {{$i18n.t('hotspot.delete')}}
  47. </div>
  48. </div>
  49. </li>
  50. </ul>
  51. <div v-else class="empty-tip">
  52. <img src="@/assets/images/default/empty_hotspot_list.png" alt="">
  53. <div>{{$i18n.t('hotspot.no_hotspot')}}</div>
  54. </div>
  55. </div>
  56. </template>
  57. <div class="goto-4dkk-tip" v-if="currentScene.type === '4dkk'">
  58. <div class="img-wrap">
  59. <img class="" src="@/assets/images/default/goto-4dage.png" alt="" draggable="false">
  60. <div class="tip-text">
  61. {{$i18n.t('screen.goto_4dkk_edit_tips')}}
  62. </div>
  63. </div>
  64. <button class="ui-button submit" @click="onClickGo4dkk">{{$i18n.t('navigation.go_scene_editor')}}</button>
  65. </div>
  66. <EditPanel
  67. class="adding-hotspot-panel"
  68. v-if="showPanel"
  69. :editTitle="editTitle"
  70. :show="showPanel"
  71. @save="save"
  72. @close="close"
  73. />
  74. </div>
  75. </template>
  76. <script>
  77. import EditPanel from "./EditPanel"
  78. import { mapGetters } from "vuex"
  79. import browser from "@/utils/browser"
  80. import hotspotTypeList from "./hotspotTypeList.js";
  81. let mapFontSize = {
  82. 12: 0.5,
  83. 17: 1.5,
  84. 20: 2,
  85. }
  86. export default {
  87. name: 'HotSpotList',
  88. components: {
  89. EditPanel,
  90. },
  91. data() {
  92. return {
  93. hotspotTypeList,
  94. showPanel: false,
  95. someData: { hotspots: [] },
  96. deleIndex: -1,
  97. editTitle: '',
  98. }
  99. },
  100. computed: {
  101. ...mapGetters({
  102. currentScene: "scene/currentScene",
  103. hotspot: 'hotspot',
  104. info: "info",
  105. }),
  106. },
  107. watch: {
  108. "$route.name": function () {
  109. this.showPanel = false
  110. },
  111. currentScene: {
  112. immediate: true,
  113. handler: function (newVal) {
  114. this.someData = newVal.someData || ""
  115. if (this.someData) {
  116. if (typeof this.someData == 'string') {
  117. try {
  118. this.someData = JSON.parse(this.someData)
  119. } catch (e) {
  120. console.error(e)
  121. return false
  122. }
  123. }
  124. if (!this.someData.hotspots) {
  125. this.someData.hotspots = []
  126. }
  127. }
  128. else {
  129. this.someData = { hotspots: [] }
  130. }
  131. },
  132. },
  133. showPanel(newVal) {
  134. this.$store.commit("UpdateIsEditingState", newVal)
  135. this.$store.commit("tags/setIsConfirmingPosi", false);
  136. },
  137. },
  138. mounted() {
  139. this.$bus.on("updateHotSpotHV", (data) => {
  140. let hptarget = this.someData.hotspots.find((item) => item.name.toLowerCase() == data.hpname.toLowerCase())
  141. console.log(hptarget);
  142. hptarget.ath = data.ath
  143. hptarget.atv = data.atv
  144. })
  145. this.$bus.on("openHotspot", (data) => {
  146. let idx = this.someData.hotspots.findIndex((item) => item.name == data)
  147. console.log(data);
  148. if (data == this.hotspot.name) {
  149. window.__krfn.utils.looktohotspot(this.$getKrpano(), this.hotspot.name)
  150. if (!this.showPanel) {
  151. this.open(this.someData.hotspots[idx])
  152. }
  153. return
  154. }
  155. if (this.editTitle == '新增' || this.editTitle == this.$i18n.t('hotspot.add')) {
  156. if (this.showPanel) {
  157. return this.$confirm({
  158. content: this.$i18n.t('hotspot.close_dialog'),
  159. ok: () => {
  160. this.deleteKRHotspot(this.hotspot)
  161. this.open(this.someData.hotspots[idx])
  162. }
  163. })
  164. }
  165. }
  166. this.open(this.someData.hotspots[idx])
  167. })
  168. },
  169. methods: {
  170. deleteKRHotspot(data) {
  171. this.$getKrpano().call("removehotspot(" + data.name + ",true);")
  172. this.$getKrpano().call("removeplugin(" + ("tooltip_" + data.name) + ",true);")
  173. },
  174. close(data) {
  175. if (data) {
  176. if (data.type == 'edit') {
  177. this.deleteKRHotspot(data.data)
  178. this.$bus.emit('addhotspot', data.data)
  179. let idx = this.someData.hotspots.findIndex(item => item.name == data.data.name)
  180. this.someData.hotspots[idx] = data.data
  181. }
  182. else {
  183. this.deleteKRHotspot(data.data)
  184. }
  185. }
  186. this.showPanel = false
  187. },
  188. updateInfo() {
  189. let iidx = this.info.scenes.findIndex(item => this.currentScene.sceneCode == item.sceneCode)
  190. if (iidx > -1) {
  191. this.info.scenes[iidx] = {
  192. ...this.currentScene
  193. }
  194. }
  195. this.$store.commit("SetInfo", this.info)
  196. },
  197. save(data) {
  198. let HV = window.__krfn.utils.getHotspotHV(this.$getKrpano(), data.name)
  199. data.ath = HV.ath
  200. data.atv = HV.atv
  201. let idx = this.someData.hotspots.findIndex((item) => item.name === data.name)
  202. if (idx <= -1) {
  203. this.someData.hotspots.push(data)
  204. }
  205. else {
  206. this.someData.hotspots[idx] = data
  207. }
  208. this.currentScene.someData = this.someData
  209. this.$msg.success(this.editTitle + this.$i18n.t('hotspot.success'))
  210. window.g_hotspotCurrentScale = mapFontSize[data.fontSize] || 1
  211. let iidx = this.info.scenes.findIndex(item => this.currentScene.sceneCode == item.sceneCode)
  212. if (iidx > -1) {
  213. this.info.scenes[iidx] = {
  214. ...this.currentScene
  215. }
  216. }
  217. this.updateInfo()
  218. },
  219. deleteHot(data) {
  220. this.someData.hotspots.splice(
  221. this.someData.hotspots.findIndex((item) => item.name === data.name),
  222. 1
  223. )
  224. this.deleteKRHotspot(data)
  225. this.currentScene.someData = this.someData
  226. this.updateInfo()
  227. this.$msg.success(this.$i18n.t('hotspot.delete')+this.$i18n.t('hotspot.success'))
  228. },
  229. open(data) {
  230. let hotspotData = null
  231. if (data.isAdd) {
  232. this.editTitle = this.$i18n.t('hotspot.add')
  233. hotspotData = {
  234. hotspotType: data.hotspotType, // 热点类型,切换场景、图片、视频、音频、链接、文本等等
  235. hotspotIconType: 'system_icon', // 热点图标的类型,系统图标(system_icon)、自定义图片(custom_image)、序列帧(serial_frame)、个性标签(personalized_tag)
  236. img: this.$config.getStaticResource('/panoassets/images/hotspot/icon/') + `img_doticon_${String(data.idxInSystemIconList).padStart(2, '0')}.svg`, // 热点图标类型为系统图标时,图标在展时段使用的url
  237. icontype: 'icon' + data.idxInSystemIconList, // 热点图标类型为系统图标时,图标的id
  238. customIconInfo: { // 热点图标类型为自定义图标时,图标的数据
  239. img: '',
  240. },
  241. serialFrameInfo: { // 热点图标类型为序列帧时,序列帧的数据
  242. url: '',
  243. frameNumber: 0, // 总帧数
  244. duration: 0, // 总播放时长(秒)
  245. },
  246. personalizedTagInfo: { // 热点图标类型为个性标签时,个性标签的数据
  247. isShowLine: true,
  248. lineDirection: 'left-top',
  249. fillColor: 'rgba(0, 0, 0, 1)',
  250. borderColor: 'rgba(0, 0, 0, 1)',
  251. textColor: 'rgba(0, 0, 0, 1)',
  252. textDirection: 'left-right',
  253. isTextWrap: false,
  254. textNumPerLine: 10,
  255. },
  256. name: "_" + this.$randomWord(true, 8, 8),
  257. hotspotTitle: this.$i18n.t('hotspot.click_to_comfirm'),
  258. fontSize: 12,
  259. type: '',
  260. link: '',
  261. titleDisplayMode: 'always', // 'always' | 'never' | 'hover' 标题显示方式
  262. titlePosition: 'top', // 'top' | 'bottom' | 'left' | 'right' | 'custom' 标题相对图标位置
  263. ath: '',
  264. atv: '',
  265. size: 1,
  266. secne: null,
  267. hyperlink: '',
  268. textarea: '',
  269. image: [], // 热点类型为图片时,图片列表
  270. audio: '',
  271. video: '',
  272. imageTextInfo: { // 热点类型为图文时,图文内容
  273. imageList: [],
  274. text: '',
  275. isApplyToAll: true,
  276. audio: {
  277. // ancestors: "",
  278. // createTime: "2022-08-01 14:30",
  279. // dirId: 1,
  280. // dirName: "根目录",
  281. // dpi: "0",
  282. // fileName: "20220801_143047668.mp3",
  283. // fileSize: "2.08MB",
  284. // icon: "0",
  285. // id: 2594,
  286. // materialType: "audio",
  287. // name: "谢海清 - 清平乐",
  288. // ossPath: "https://ossxiaoan.4dage.com/720yun_fd_manage/fodder/20220801_143047668.mp3",
  289. // previewIcon: "",
  290. // sceneCode: "0",
  291. // status: 0,
  292. // tempId: "u_4zK9YIFW",
  293. // type: "audio",
  294. // updateTime: "2022-11-01 19:49",
  295. // userId: "13825625448",
  296. }
  297. },
  298. phoneInfo: { // 热点类型为电话时,对应数据
  299. phone: '',
  300. },
  301. pdfInfo: { // 热点类型为pdf时,对应数据
  302. name: '',
  303. url: '',
  304. },
  305. articleInfo: {
  306. html: '',
  307. }
  308. }
  309. } else {
  310. hotspotData = browser.CloneObject(data)
  311. /**
  312. * v1.3新增
  313. */
  314. if (!hotspotData.hotspotIconType) {
  315. hotspotData.hotspotIconType = 'system_icon'
  316. }
  317. if (!hotspotData.customIconInfo) {
  318. hotspotData.customIconInfo = {
  319. img: '',
  320. }
  321. }
  322. if (!hotspotData.serialFrameInfo) {
  323. hotspotData.serialFrameInfo = {
  324. url: '',
  325. frameNumber: 0,
  326. duration: 0,
  327. }
  328. }
  329. hotspotData.personalizedTagInfo = {
  330. isShowLine: true,
  331. lineDirection: 'left-top',
  332. fillColor: 'rgba(0, 0, 0, 1)',
  333. borderColor: 'rgba(0, 0, 0, 1)',
  334. textColor: 'rgba(0, 0, 0, 1)',
  335. textDirection: 'left-right',
  336. isTextWrap: false,
  337. textNumPerLine: 10,
  338. }
  339. // v1.3把visible: Boolean换成了titleDisplayMode
  340. if (hotspotData.visible) {
  341. hotspotData.titleDisplayMode = 'always'
  342. } else if (hotspotData.visible === false) {
  343. hotspotData.titleDisplayMode = 'never'
  344. }
  345. if (!hotspotData.titlePosition) {
  346. hotspotData.titlePosition = 'top'
  347. }
  348. if (!hotspotData.imageTextInfo) {
  349. hotspotData.imageTextInfo = {
  350. imageList: [],
  351. text: '',
  352. isApplyToAll: true,
  353. audio: {}
  354. }
  355. }
  356. if (!hotspotData.phoneInfo) {
  357. hotspotData.phoneInfo = {
  358. phone: '',
  359. }
  360. }
  361. if (!hotspotData.pdfInfo) {
  362. hotspotData.pdfInfo = {
  363. name: '',
  364. url: '',
  365. }
  366. }
  367. if (!hotspotData.articleInfo) {
  368. hotspotData.articleInfo = {
  369. html: '',
  370. }
  371. }
  372. /**
  373. * end of v1.3新增
  374. */
  375. }
  376. this.$store.commit("SetHotspot", hotspotData)
  377. this.showPanel = true
  378. if (!data.isAdd) {
  379. this.editTitle = this.$i18n.t('hotspot.edit')
  380. window.__krfn.utils.looktohotspot(this.$getKrpano(), data.name)
  381. }
  382. },
  383. clickoutside() {
  384. if (this.deleIndex > -1) {
  385. this.deleIndex = -1
  386. }
  387. },
  388. onClickGo4dkk() {
  389. window.open('/#/scene')
  390. },
  391. },
  392. }
  393. </script>
  394. <style lang="less" scoped>
  395. .hot-spot-list {
  396. padding: 20px;
  397. display: flex;
  398. flex-direction: column;
  399. background: #252526;
  400. position: relative;
  401. > .title {
  402. flex: 0 0 auto;
  403. font-size: 18px;
  404. color: #fff;
  405. flex: 0 0 auto;
  406. margin-bottom: 24px;
  407. >i {
  408. font-size: 12px;
  409. position: relative;
  410. top: -2px;
  411. }
  412. }
  413. > .hotspot-type-list {
  414. flex: 0 0 auto;
  415. margin-right: -10px;
  416. > .hotspot-type-item {
  417. position: relative;
  418. display: inline-flex;
  419. flex-direction: column;
  420. justify-content: center;
  421. align-items: center;
  422. width: 72px;
  423. height: 72px;
  424. background: #313131;
  425. border-radius: 2px;
  426. border: 1px solid #404040;
  427. margin-right: 9px;
  428. margin-bottom: 9px;
  429. cursor: pointer;
  430. > .icon {
  431. width: 28px;
  432. height: 28px;
  433. margin-bottom: 3px;
  434. }
  435. > .type-name {
  436. font-size: 12px;
  437. color: #FFFFFF;
  438. }
  439. > .exp-tag {
  440. position: absolute;
  441. top: 0;
  442. right: 0;
  443. width: 30px;
  444. height: 30px;
  445. }
  446. }
  447. }
  448. .total-count {
  449. flex: 0 0 auto;
  450. margin-top: 24px;
  451. font-size: 18px;
  452. color: #FFFFFF;
  453. .number {
  454. font-size: 14px;
  455. color: rgba(255, 255, 255, 0.6);
  456. position: relative;
  457. top: -1px;
  458. }
  459. }
  460. .hots {
  461. flex: 1 0 1px;
  462. margin-top: 16px;
  463. background: available;
  464. background: #1A1B1D;
  465. border-radius: 4px;
  466. border: 1px solid #404040;
  467. position: relative;
  468. overflow: auto;
  469. ul {
  470. padding: 10px;
  471. li {
  472. position: relative;
  473. height: 40px;
  474. border-radius: 2px;
  475. display: flex;
  476. align-items: center;
  477. padding: 0 5px 0 10px;
  478. &:hover {
  479. background: #252526;
  480. .icon-delete {
  481. display: block;
  482. }
  483. }
  484. >.hot-spot-thumb {
  485. width: 18px;
  486. }
  487. >.hot-spot-title {
  488. flex: 1 1 auto;
  489. margin-left: 10px;
  490. text-overflow: ellipsis;
  491. overflow: hidden;
  492. white-space: nowrap;
  493. }
  494. >.icon-delete {
  495. margin-left: 12px;
  496. display: none;
  497. cursor: pointer;
  498. padding: 5px;
  499. &:hover {
  500. color: #fa5555;
  501. }
  502. }
  503. >.deletion-confirm-wrap {
  504. position: absolute;
  505. top: 0;
  506. bottom: 0;
  507. right: 0;
  508. width: 44px;
  509. overflow: hidden;
  510. pointer-events: none;
  511. border-top-right-radius: 2px;
  512. border-bottom-right-radius: 2px;
  513. >.deletion-confirm {
  514. position: absolute;
  515. top: 0;
  516. bottom: 0;
  517. width: 100%;
  518. background: #FA5555;
  519. transition: right 0.3s;
  520. cursor: pointer;
  521. text-align: center;
  522. font-size: 12px;
  523. color: #fff;
  524. pointer-events: auto;
  525. &::after {
  526. content: '';
  527. height: 100%;
  528. vertical-align: middle;
  529. display: inline-block;
  530. }
  531. &.show {
  532. right: 0;
  533. }
  534. &.hide {
  535. right: -44px;
  536. }
  537. }
  538. }
  539. }
  540. }
  541. .empty-tip {
  542. text-align: center;
  543. position: absolute;
  544. text-align: center;
  545. width: 100%;
  546. top: 50%;
  547. transform: translateY(-50%);
  548. img {
  549. width: 125px;
  550. }
  551. div {
  552. margin-top: 20px;
  553. color: rgba(255, 255, 255, 0.6);
  554. font-size: 14px;
  555. }
  556. }
  557. }
  558. .ui-button {
  559. width: 100%;
  560. }
  561. .adding-hotspot-panel {
  562. position: absolute;
  563. top: 0;
  564. height: 100%;
  565. right: 0;
  566. width: 100%;
  567. }
  568. .goto-4dkk-tip {
  569. > .img-wrap {
  570. position: relative;
  571. width: 100%;
  572. > .img {
  573. width: 100%;
  574. }
  575. > .tip-text {
  576. position: absolute;
  577. left: 50%;
  578. bottom: 32px;
  579. transform: translateX(-50%);
  580. font-size: 14px;
  581. color: #fff;
  582. opacity: 0.6;
  583. white-space: pre;
  584. }
  585. }
  586. > button {
  587. margin-top: 16px;
  588. width: 100%;
  589. }
  590. }
  591. }
  592. </style>