فهرست منبع

Merge branch 'dev' of http://192.168.0.115:3000/chenzhiguang/qjkankan_v1.1.1 into dev

tremble 3 سال پیش
والد
کامیت
b997af011e

+ 1 - 1
packages/qjkankan-editor/src/Store/index.js

@@ -45,7 +45,7 @@ const store = new Vuex.Store({
     isEditing: state => state.isEditing,
     info: state => state.info,
     catalogTopology: (state) => {
-      if (!state.info) {
+      if (!state.info || !state.info.catalogRoot || !state.info.catalogs) {
         return
       }
       //四层:root,level1(一级分类),level2(二级分类或直属于一级分类的场景), level3(场景)

BIN
packages/qjkankan-editor/src/assets/images/default/empty_hotspot_list.png


+ 2 - 2
packages/qjkankan-editor/src/components/sceneGroupInEditor.vue

@@ -16,7 +16,7 @@
       }"
     >
       <i class="iconfont icon-edit_input_arrow icon-expand" :class="isExpanded ? '' : 'collapsed'"></i>
-      <i v-show="isExpanded" class="iconfont icon-editor_folder_on folder_expalded"></i>
+      <i v-show="isExpanded" class="iconfont icon-editor_folder_on folder_expanded"></i>
       <i v-show="!isExpanded" class="iconfont icon-editor_folder_off folder_collapsed"></i>
       <template v-if="!isRenaming">
         <span class="group-name" v-title="groupNode.name">{{groupNode.name}}</span>
@@ -394,7 +394,7 @@ export default {
         transform: scale(0.7) rotate(-90deg);
       }
     }
-    > .folder_expalded {
+    > .folder_expanded {
       font-size: 16px;
       margin-left: 7px;
     }

+ 11 - 6
packages/qjkankan-editor/src/utils/other.js

@@ -79,7 +79,7 @@ export function isValidPhoneNumber(value) {
   return reg.test(value)
 }
 
-// 深拷贝
+// 深拷贝,为了解决循环引用和共同引用的问题,引入了WeakMap,又因为引入WeakMap可能会导致被拷贝对象被挂上【作为WeakMap的探针的】匿名函数(是pollyfill的行为吧?),所以不会拷贝非根元素的匿名函数。
 export function deepClone(target, hash = new WeakMap()) {
   // 定义一个变量
   let result = null
@@ -91,8 +91,10 @@ export function deepClone(target, hash = new WeakMap()) {
       result = [] // 将result赋值为一个数组,并且执行遍历
       hash.set(target, result)
       for (let i in target) {
-        // 递归克隆数组中的每一项
-        result.push(deepClone(target[i], hash))
+        if (!(typeof(target[i]) === 'function' && !target.name)) {
+          // 递归克隆数组中的每一项
+          result.push(deepClone(target[i], hash))
+        }
       }
       // 判断如果当前的值是null的话;直接赋值为null
     } else if (target === null) {
@@ -105,11 +107,14 @@ export function deepClone(target, hash = new WeakMap()) {
       result = {}
       hash.set(target, result)
       for (let i in target) {
-        result[i] = deepClone(target[i], hash)
+        if (!(typeof(target[i]) === 'function' && !target.name)) {
+          result[i] = deepClone(target[i], hash)
+        }
       }
     }
-    // 如果不是对象的话,就是基本数据类型,那么直接赋值
-  } else {
+  } else if (typeof target === 'function') {
+    result = target
+  } else { // 如果不是对象也不是函数,直接赋值
     result = target
   }
   // 返回最终结果

+ 390 - 0
packages/qjkankan-editor/src/views/hotspot/HotSpotList.vue

@@ -0,0 +1,390 @@
+<template>
+  <div class="hot-spot-list" app-border dir-left>
+    <div class="title">
+      热点设置
+      <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="'在全景图中添加图标热点,并设置热点的效果。'"/>
+    </div>
+    <button
+      class="ui-button submit"
+      :class="{ disable: !activeItem }"
+      @click="open(null)"
+    >
+      添加热点
+    </button>
+
+    <div class="total-count">当前全景图热点
+      <span class="number">({{ someData.hotspots.length }})</span>
+    </div>
+    <div class="hots">
+      <ul v-if="someData.hotspots.length > 0">
+        <li
+          v-for="(item, key) in someData.hotspots"
+          :key="key"
+          @click="open(item)"
+        >
+          <img class="hot-spot-thumb" :src="item.img" alt="">
+          <span class="hot-spot-title" v-title="item.hotspotTitle">{{ item.hotspotTitle }}</span>
+          <i
+            class="iconfont icon-editor_list_delete icon-delete"
+            v-tooltip="'删除'"
+            @click.stop="deleIndex = key"
+          />
+          <div class="deletion-confirm-wrap">
+            <div class="deletion-confirm" :class="deleIndex == key ? 'show' : 'hide'"
+              v-clickoutside="clickoutside"
+              @click.stop="deleteHot(item)"
+            >
+              删除
+            </div>
+          </div>
+        </li>
+      </ul>
+      <div v-else class="empty-tip">
+        <img src="@/assets/images/default/empty_hotspot_list.png" alt="">
+        <div>暂无热点信息~</div>
+      </div>
+    </div>
+    <eidt-panel
+      v-if="showPanel"
+      :editTitle="editTitle"
+      @save="save"
+      @select="
+        (data) => {
+          $emit('select', data);
+        }
+      "
+      :show="showPanel"
+      @close="close"
+    ></eidt-panel>
+  </div>
+</template>
+
+<script>
+import EidtPanel from "./EditPanel"
+import { mapGetters } from "vuex"
+import browser from "@/utils/browser"
+export default {
+  name: 'HotSpotList',
+  components: {
+    EidtPanel,
+  },
+  computed: {
+    ...mapGetters({
+      activeItem: "activeItem",
+      hotspot: 'hotspot',
+      info: "info"
+    }),
+  },
+  data() {
+    return {
+      editLink: "",
+      showPanel: false,
+      someData: { hotspots: [] },
+      deleIndex: -1,
+      editTitle: "编辑",
+    }
+  },
+  watch: {
+    "$route.name": function () {
+      this.showPanel = false
+    },
+    activeItem: {
+      immediate: true,
+      handler: function (newVal) {
+        this.someData = newVal.someData || ""
+        if (this.someData) {
+          if (typeof this.someData == 'string') {
+            try {
+              this.someData = JSON.parse(this.someData)
+            } catch (e) {
+              console.error(e)
+              return false
+            }
+          }
+          if (!this.someData.hotspots) {
+            this.someData.hotspots = []
+          }
+        }
+        else {
+          this.someData = { hotspots: [] }
+        }
+        console.log(this.someData.hotspots, 111111)
+      },
+    },
+    showPanel(newVal) {
+      this.$store.commit("UpdateIsEditingState", newVal)
+      this.$bus.emit("canEdit", !newVal)
+    },
+  },
+  mounted() {
+    this.$bus.on("openHotspot", (data) => {
+      let idx = this.someData.hotspots.findIndex((item) => item.name == data)
+      let beforeIdx = this.someData.hotspots.findIndex((item) => item.name == this.hotspot.name)
+      if (beforeIdx == idx) {
+        return
+      }
+      if (this.editTitle == '新增') {
+        if (this.showPanel) {
+          return this.$confirm({
+            content: "热点内容未编辑完,确定要关闭吗",
+            ok: () => {
+              this.deleteKRHotspot(this.hotspot)
+              this.open(this.someData.hotspots[idx])
+            }
+          })
+        }
+
+      }
+
+      this.open(this.someData.hotspots[idx])
+
+    })
+  },
+  methods: {
+    deleteKRHotspot(data) {
+      let krpano = document.getElementById("krpanoSWFObject")
+      krpano.call("removehotspot(" + data.name + ",true);")
+      krpano.call("removeplugin(" + ("tooltip_" + data.name) + ",true);")
+    },
+    close(data) {
+      if (data) {
+        if (data.type == 'edit') {
+          this.deleteKRHotspot(data.data)
+          this.$bus.emit('addhotspot', data.data)
+          let idx = this.someData.hotspots.findIndex(item => item.name == data.data.name)
+          this.someData.hotspots[idx] = data.data
+        }
+        else {
+          this.deleteKRHotspot(data.data)
+        }
+      }
+      this.showPanel = false
+    },
+
+    updateInfo() {
+      let iidx = this.info.scenes.findIndex(item => this.activeItem.sceneCode == item.sceneCode)
+      if (iidx > -1) {
+        this.info.scenes[iidx] = {
+          ...this.activeItem
+        }
+      }
+      this.$store.commit("SetInfo", this.info)
+    },
+    save(data) {
+      var krpano = document.getElementById("krpanoSWFObject")
+      let HV = window.__krfn.utils.getHotspotHV(krpano, data.name)
+      data.ath = HV.ath
+      data.atv = HV.atv
+      let idx = this.someData.hotspots.findIndex((item) => item.name === data.name)
+      if (idx <= -1) {
+        this.someData.hotspots.push(data)
+      }
+      else {
+        this.someData.hotspots[idx] = data
+      }
+
+      this.activeItem.someData = this.someData
+      this.$msg.success(this.editTitle + "成功")
+
+      let iidx = this.info.scenes.findIndex(item => this.activeItem.sceneCode == item.sceneCode)
+      if (iidx > -1) {
+        this.info.scenes[iidx] = {
+          ...this.activeItem
+        }
+      }
+
+      this.updateInfo()
+
+    },
+    deleteHot(data) {
+      this.someData.hotspots.splice(
+        this.someData.hotspots.findIndex((item) => item.name === data.name),
+        1
+      )
+      this.deleteKRHotspot(data)
+      this.activeItem.someData = this.someData
+      this.updateInfo()
+      this.$msg.success("删除成功")
+    },
+    open(data) {
+      this.editTitle = "新增"
+      let temp = data ? browser.CloneObject(data) : {
+        name: "_" + this.$randomWord(true, 8, 8),
+        hotspotTitle: '',
+        fontSize: 12,
+        type: '',
+        img: '',
+        link: '',
+        visible: true,
+        ath: '',
+        atv: '',
+        icontype: 'ditu',
+        size: 1,
+        hotspotType: 'scene',
+        secne: '',
+        hyperlink: '',
+        textarea: '',
+        image: [],
+        audio: '',
+        video: ''
+      }
+
+      this.$store.commit("SetHotspot", temp)
+      this.showPanel = true
+
+      if (data) {
+        this.editLink = temp.link
+        this.editTitle = "编辑"
+        var krpano = document.getElementById("krpanoSWFObject")
+        window.__krfn.utils.looktohotspot(krpano, data.name)
+      }
+    },
+    clickoutside() {
+      if (this.deleIndex > -1) {
+        this.deleIndex = -1
+      }
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.hot-spot-list {
+  padding: 20px;
+  display: flex;
+  flex-direction: column;
+  background: #252526;
+  > .title {
+    font-size: 18px;
+    color: #fff;
+    flex: 0 0 auto;
+    > i {
+      font-size: 12px;
+      position: relative;
+      top: -2px;
+    }
+  }
+  > button {
+    flex: 0 0 auto;
+    width: 100%;
+    margin-top: 16px;
+    i {
+      font-size: 14px;
+    }
+  }
+  .total-count {
+    flex: 0 0 auto;
+    margin-top: 24px;
+    font-size: 18px;
+    color: #FFFFFF;
+    .number {
+      font-size: 14px;
+      color: rgba(255, 255, 255, 0.6);
+      position: relative;
+      top: -1px;
+    }
+  }
+  .hots {
+    flex: 1 0 1px;
+    margin-top: 16px;
+    background: available;
+    background: #1A1B1D;
+    border-radius: 4px;
+    border: 1px solid #404040;
+    position: relative;
+    overflow: auto;
+    ul {
+      padding: 10px;
+      li {
+        position: relative;
+        height: 40px;
+        border-radius: 2px;
+        display: flex;
+        align-items: center;
+        padding: 0 10px;
+        &:hover {
+          background: #252526;
+          .icon-delete {
+            display: block;
+          }
+        }
+        > .hot-spot-thumb {
+          width: 18px;
+        }
+        > .hot-spot-title {
+          flex: 1 1 auto;
+          margin-left: 10px;
+          text-overflow: ellipsis;
+          overflow: hidden;
+          white-space: nowrap;
+        }
+        > .icon-delete {
+          margin-left: 12px;
+          display: none;
+          cursor: pointer;
+          &:hover {
+            color: #fa5555;
+          }
+        }
+        > .deletion-confirm-wrap {
+          position: absolute;
+          top: 0;
+          bottom: 0;
+          right: 0;
+          width: 44px;
+          overflow: hidden;
+          pointer-events: none;
+          border-top-right-radius: 2px;
+          border-bottom-right-radius: 2px;
+          > .deletion-confirm {
+            position: absolute;
+            top: 0;
+            bottom: 0;
+            width: 100%;
+            background: #FA5555;
+            transition: right 0.3s;
+            cursor: pointer;
+            text-align: center;
+            font-size: 12px;
+            color: #fff;
+            pointer-events: auto;
+            &::after {
+              content: '';
+              height: 100%;
+              vertical-align: middle;
+              display: inline-block;
+            }
+            &.show {
+              right: 0;
+            }
+            &.hide {
+              right: -44px;
+            }
+          }
+        }
+      }
+    }
+
+    .empty-tip {
+      text-align: center;
+      position: absolute;
+      text-align: center;
+      width: 100%;
+      top: 50%;
+      transform: translateY(-50%);
+      img {
+        width: 125px;
+      }
+      div {
+        margin-top: 20px;
+        color: rgba(255, 255, 255, 0.6);
+        font-size: 14px;
+      }
+    }
+  }
+
+  .ui-button {
+    width: 100%;
+  }
+}
+</style>

+ 5 - 5
packages/qjkankan-editor/src/views/hotspot/index.vue

@@ -1,7 +1,7 @@
 <template>
   <!-- 编辑器-热点 -->
   <div class="editor-hotspot">
-    <setting class="hotspot-settings" @select="handleSelectScene"></setting>
+    <HotSpotList class="hot-spot-list" @select="handleSelectScene"></HotSpotList>
     <div class="dialog" v-if="show">
       <Select
         @updateList="undatePano"
@@ -40,13 +40,13 @@
   </div>
 </template>
 <script>
-import Setting from "./Setting.vue";
+import HotSpotList from "./HotSpotList.vue";
 import Select from "@/components/select";
 
 export default {
-  name: "home",
+  name: "HotSpot",
   components: {
-    Setting,
+    HotSpotList,
     Select,
   },
   mounted(){
@@ -107,7 +107,7 @@ export default {
 .editor-hotspot {
   height: 100%;
   position: relative;
-  .hotspot-settings {
+  .hot-spot-list {
     position: absolute;
     right: 0;
     width: 274px;