EditPanel.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. <template>
  2. <transition
  3. appear
  4. name="custom-classes-transition"
  5. enter-active-class="animated slideInRight speed"
  6. leave-active-class="animated slideOutRight speed"
  7. >
  8. <div class="hots-panel" v-show="show">
  9. <div class="ui-between header">
  10. <span>{{editTitle}}热点</span>
  11. <i class="iconfont icon_close" @click="confirmCancel"></i>
  12. </div>
  13. <div class="content" ref="content">
  14. <div class="icon-setting">
  15. <div class="icon-setting-title">热点图标</div>
  16. <div class="remark">选择图标</div>
  17. <div class="icon-list">
  18. <div class="margin-handler-layer">
  19. <ul>
  20. <li
  21. :class="{ active: item.id == hotspot.icontype }"
  22. v-for="(item,i) in hotStyle"
  23. @click="addhotspot(item)"
  24. :key="i"
  25. >
  26. <img :src="item.thumb" alt="">
  27. </li>
  28. </ul>
  29. </div>
  30. </div>
  31. <div class="bars">
  32. <RangeItem :value="rang" @input="onRangeChange" />
  33. </div>
  34. </div>
  35. <div class="title-setting">
  36. <div class="title-setting-title">标题设置</div>
  37. <div class="switch-wrapper">
  38. <span class="label">是否显示标题</span>
  39. <Switcher :value="hotspot.visible" @change="hotspot.visible = !hotspot.visible"></Switcher>
  40. </div>
  41. <div class="title-input-wrapper">
  42. <input
  43. v-model.trim="hotspot.hotspotTitle"
  44. type="text"
  45. maxlength="15"
  46. placeholder="请输入标题,限15字"
  47. />
  48. <span class="count">{{hotspot.hotspotTitle.length}}/15</span>
  49. </div>
  50. </div>
  51. <div class="effect-setting">
  52. <div class="effect-setting-title">效果设置</div>
  53. <combox
  54. class="combox"
  55. :data="hotSpotTypeList"
  56. :selected-id="hotspot.hotspotType"
  57. :bottomSpace="comboxBottomSpace"
  58. @change="onhotSpotTypeChange"
  59. ></combox>
  60. <component
  61. class="effect-setting-component"
  62. @sceneSelect="handleSceneSelect"
  63. :scene="hotspot.secne"
  64. @imageChange="data=>{hotspot.image=data}"
  65. :image="hotspot.image"
  66. @linkChange="data=>{hotspot.hyperlink=data}"
  67. :link="hotspot.hyperlink"
  68. @textChange="data=>{hotspot.textarea=data}"
  69. :textarea="hotspot.textarea"
  70. @audioChange="data=>{hotspot.audio=data}"
  71. :audio="hotspot.audio"
  72. @videoChange="data=>{hotspot.video=data}"
  73. :video="hotspot.video"
  74. :is="effectSettingComponent"
  75. />
  76. </div>
  77. </div>
  78. <div class="ui-between footer" app-border dir-top>
  79. <button class="ui-button deepcancel" :class="{disable: false}" @click="confirmCancel">取消</button>
  80. <button class="ui-button submit" :class="{disable: false}" @click="save">完成</button>
  81. </div>
  82. </div>
  83. </transition>
  84. </template>
  85. <script>
  86. import RangeItem from "@/components/rangeItem/index.vue";
  87. import Combox from "@/components/shared/Combox";
  88. import { mapGetters } from "vuex";
  89. import Switcher from "@/components/shared/Switcher.vue";
  90. let HTMap = {
  91. scene:{
  92. key:'secne',
  93. type:'Object',
  94. errortxt:'请选择场景'
  95. },
  96. audio:{
  97. key:'audio',
  98. type:'String',
  99. errortxt:'请选择音频'
  100. },
  101. video:{
  102. key:'video',
  103. type:'String',
  104. errortxt:'请选择视频'
  105. },
  106. image:{
  107. key:'image',
  108. type:'Array',
  109. errortxt:'请选择图片'
  110. },
  111. link:{
  112. key:'hyperlink',
  113. type:'String',
  114. errortxt:'请输入超链接'
  115. },
  116. textarea:{
  117. key:'textarea',
  118. type:'String',
  119. errortxt:'请输入文本'
  120. }
  121. }
  122. export default {
  123. props: ['show','data','editTitle'],
  124. components:{
  125. RangeItem,
  126. Combox,
  127. Switcher,
  128. },
  129. data(){
  130. let cdn = this.$config.getStaticResource('/panoassets/images/hotspot/icon/')
  131. let hotStyle = []
  132. for (let i = 0; i < 12; i++) {
  133. hotStyle[i] = {
  134. id:'icon'+(i+1),
  135. img:cdn+`img_doticon_${String(i+1).padStart(2, '0')}.svg`,
  136. thumb:cdn+`img_doticon_${String(i+1).padStart(2, '0')}.svg`
  137. }
  138. }
  139. return {
  140. canSave:false,
  141. hotSpotTypeList:[
  142. {
  143. id:'scene',
  144. name:'场景切换'
  145. },
  146. {
  147. id:'link',
  148. name:'超链接'
  149. },
  150. {
  151. id:'textarea',
  152. name:'文本'
  153. },
  154. {
  155. id:'image',
  156. name:'图片'
  157. },
  158. {
  159. id:'audio',
  160. name:'音频'
  161. },
  162. {
  163. id:'video',
  164. name:'视频'
  165. }
  166. ],
  167. hotStyle,
  168. rang: {
  169. label: '图标大小',
  170. unit: "倍",
  171. gradient: 0.5,
  172. value: 1,
  173. min: 0.5,
  174. max: 2,
  175. },
  176. selectItem:'',
  177. styIcon:'',
  178. linkicon:'',
  179. infoItem: '',
  180. isAdd:true,
  181. comboxBottomSpace: 0,
  182. }
  183. },
  184. watch:{
  185. 'hotspot.hotspotTitle':function () {
  186. this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].html',this.hotspot.hotspotTitle)
  187. },
  188. 'hotspot.visible':function () {
  189. this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].visible',this.hotspot.visible)
  190. },
  191. 'hotspot.size': {
  192. immediate:true,
  193. handler:function (newVal) {
  194. let h = 52
  195. let scaleH = h*newVal
  196. let offset = '-130%'
  197. this.rang = { ...this.rang, value: newVal }
  198. this.$getKrpano().set(`hotspot[${this.hotspot.name}].height`,scaleH)
  199. if (newVal < 1) {
  200. offset = '-200%'
  201. }
  202. if (newVal > 1) {
  203. offset = '-100%'
  204. }
  205. this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].y',`${offset}`)
  206. }
  207. },
  208. 'hotspot.fontSize':{
  209. handler:function (newVal) {
  210. this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].css',`text-align:center; color:#FFFFFF;
  211. font-family:STXihei;font-size:${newVal}px;`)
  212. }
  213. },
  214. show(newVal){
  215. if (!newVal) {
  216. this.$bus.removeListener('selectUrl',this.listerFn)
  217. }
  218. }
  219. },
  220. beforeDestroy(){
  221. this.$bus.removeListener('selectUrl',this.listerFn)
  222. },
  223. computed:{
  224. ...mapGetters({
  225. hotspot:'hotspot',
  226. backupHotSpot:'backupHotSpot'
  227. }),
  228. effectSettingComponent(){
  229. let tmp = this.hotspot.hotspotType
  230. return () => import(`./hotspotType/${tmp}.vue`);
  231. },
  232. },
  233. mounted(){
  234. this.selectItem = {
  235. sceneCode: this.infoItem.link
  236. }
  237. this.$bus.on('selectUrl',this.listerFn)
  238. this.$bus.on('delhotspot',()=>{
  239. this.cancel()
  240. })
  241. this.$nextTick(()=>{
  242. if (this.editTitle != '编辑') {
  243. this.addhotspot(this.hotStyle[0])
  244. }
  245. this.comboxBottomSpace = this.$refs.content.getBoundingClientRect().bottom
  246. })
  247. },
  248. methods: {
  249. handleSceneSelect(data){
  250. this.hotspot.secne= data
  251. },
  252. onhotSpotTypeChange(data){
  253. this.hotspot.hotspotType = data.id
  254. },
  255. onRangeChange(data) {
  256. this.rang = { ...this.rang, value: data.value }
  257. this.hotspot.size = data.value
  258. switch (data.value) {
  259. case 0.5:
  260. this.hotspot.fontSize = 12
  261. break;
  262. case 1:
  263. this.hotspot.fontSize = 14
  264. break;
  265. case 1.5:
  266. this.hotspot.fontSize = 17
  267. break;
  268. case 2:
  269. this.hotspot.fontSize = 20
  270. break;
  271. default:
  272. console.error('unexpected range value: ', data.value);
  273. break;
  274. }
  275. },
  276. listerFn(data){
  277. this.selectItem = {
  278. sceneCode: data.sceneCode
  279. }
  280. this.infoItem.link = data.sceneCode
  281. this.infoItem.thumb = data.icon
  282. },
  283. confirmCancel(){
  284. this.$confirm({
  285. content: "热点内容未编辑完,确定要关闭吗",
  286. ok: () => {
  287. this.cancel()
  288. }
  289. });
  290. },
  291. cancel() {
  292. this.$store.commit("SetHotspot", this.backupHotSpot);
  293. this.$emit("close",{
  294. type:this.editTitle=='编辑'?'edit':'add',
  295. data:this.backupHotSpot
  296. });
  297. },
  298. reset(data){
  299. this.$bus.emit('edithotspotTitle',data)
  300. this.$bus.emit('edithotspotTitleisShow',data)
  301. this.$getKrpano().set(`hotspot[${data.name}].url`,data.img)
  302. },
  303. save() {
  304. let {img,hotspotTitle,hotspotType} = this.hotspot
  305. let item = HTMap[hotspotType]
  306. if (!img) {
  307. return this.$alert({
  308. content: "请选择热点图标",
  309. });
  310. }
  311. if (!hotspotTitle.trim()) {
  312. return this.$alert({
  313. content: "请输入热点标题",
  314. });
  315. }
  316. if (!this.hotspot[item.key]||(item.type == 'Array'&&this.hotspot[item.key].length<=0)) {
  317. return this.$alert({
  318. content: `${item.errortxt}`,
  319. });
  320. }
  321. this.$store.commit("SetHotspot", this.hotspot);
  322. this.$emit("close");
  323. this.$emit("save",this.hotspot);
  324. },
  325. addhotspot(data){
  326. if (this.isAdd) {
  327. this.isAdd = false
  328. this.hotspot.img = data.img
  329. this.hotspot.icontype = data.id
  330. this.styIcon = data.id
  331. this.$bus.emit('addhotspot',this.hotspot)
  332. this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].css',`text-align:center; color:#FFFFFF;
  333. font-family:STXihei;font-size:${this.hotspot.fontSize}px;`)
  334. }
  335. else{
  336. this.hotspot.img = data.img
  337. this.hotspot.icontype = data.id
  338. this.styIcon = data.id
  339. this.$getKrpano().set(`hotspot[${this.hotspot.name}].url`,data.img)
  340. this.$getKrpano().set(`hotspot[${this.hotspot.name}].hotspottitle`,this.hotspot.hotspotTitle)
  341. }
  342. }
  343. }
  344. };
  345. </script>
  346. <style lang="less" scoped>
  347. .hots-panel {
  348. background: #1A1B1D;
  349. z-index: 10;
  350. display: flex;
  351. flex-direction: column;
  352. .header {
  353. padding: 20px;
  354. display: flex;
  355. font-size: 18px;
  356. color: #fff;
  357. flex: 0 0 auto;
  358. .icon_close {
  359. color: rgba(255, 255, 255, 0.6);
  360. cursor: pointer;
  361. }
  362. }
  363. .content {
  364. padding: 20px 20px 14px 20px;
  365. background: #252526;
  366. flex: 1 0 1px;
  367. overflow: auto;
  368. .icon-setting {
  369. .icon-setting-title {
  370. font-size: 18px;
  371. color: #FFFFFF;
  372. }
  373. .remark {
  374. margin-top: 16px;
  375. font-size: 14px;
  376. color: #ababab;
  377. }
  378. .icon-list {
  379. margin-top: 16px;
  380. height: 158px;
  381. background: #1A1B1D;
  382. border-radius: 2px;
  383. border: 1px solid #404040;
  384. overflow: auto;
  385. padding: 4px;
  386. > .margin-handler-layer {
  387. overflow: hidden;
  388. ul {
  389. display: flex;
  390. align-items: center;
  391. flex-wrap: wrap;
  392. margin-right: -17px;
  393. margin-bottom: -17px;
  394. li {
  395. cursor: pointer;
  396. margin-right: 17px;
  397. margin-bottom: 17px;
  398. width: 38px;
  399. height: 38px;
  400. border: solid 2px transparent;
  401. border-radius: 4px;
  402. display: flex;
  403. align-items: center;
  404. justify-content: center;
  405. &.active {
  406. border-color: #0076f6;
  407. }
  408. }
  409. }
  410. }
  411. }
  412. .bars{
  413. margin-top: 16px;
  414. }
  415. }
  416. .title-setting {
  417. margin-top: 24px;
  418. .title-setting-title {
  419. font-size: 18px;
  420. color: #FFFFFF;
  421. }
  422. .switch-wrapper {
  423. display: flex;
  424. align-items: center;
  425. justify-content: space-between;
  426. margin-top: 18px;
  427. .label {
  428. color: rgba(255, 255, 255, 0.6);
  429. font-size: 14px;
  430. }
  431. }
  432. > .title-input-wrapper {
  433. position: relative;
  434. border: 1px solid rgba(151, 151, 151, 0.2);
  435. padding: 0 16px;
  436. background: #1A1B1D;
  437. border-radius: 2px;
  438. height: 36px;
  439. width: 100%;
  440. margin-top: 18px;
  441. &:focus-within {
  442. border-color: #0076F6;
  443. }
  444. > input {
  445. border: none;
  446. background: transparent;
  447. outline: none;
  448. height: 100%;
  449. width: calc(100% - 50px);
  450. padding: 0;
  451. color: #fff;
  452. letter-spacing: 1px;
  453. font-size: 14px;
  454. }
  455. > .count {
  456. position: absolute;
  457. top: 50%;
  458. transform: translateY(-50%);
  459. right: 16px;
  460. font-size: 14px;
  461. color: rgba(255, 255, 255, 0.2);
  462. }
  463. }
  464. }
  465. .effect-setting {
  466. margin-top: 16px;
  467. .effect-setting-title {
  468. font-size: 18px;
  469. color: #FFFFFF;
  470. }
  471. .combox {
  472. margin-top: 16px;
  473. }
  474. .effect-setting-component {
  475. margin-top: 16px;
  476. }
  477. }
  478. }
  479. .footer {
  480. flex: 0 0 auto;
  481. padding: 15px;
  482. background: #252526;
  483. .deepcancel {
  484. margin-right: 10px;
  485. }
  486. .ui-button {
  487. width: 112px;
  488. }
  489. }
  490. }
  491. </style>