gemercheung 2 år sedan
förälder
incheckning
75dd090bb2

+ 1 - 0
packages/qjkankan-editor/src/api/index.js

@@ -47,6 +47,7 @@ export function getPanoInfo(data, ok, no) {
  * @param {*} no 
  */
 export function getSceneInfomation(data, ok, no) {
+  debugger
   return http.get(`/api/scene/getInfo?num=${data.id}&_=${Math.random()}`, {}, ok, no)
 }
 

BIN
packages/qjkankan-editor/src/assets/images/icons/hotspot-type/image-old.png


BIN
packages/qjkankan-editor/src/assets/images/icons/hotspot-type/image.png


+ 156 - 116
packages/qjkankan-editor/src/components/sceneGroupInEditor.vue

@@ -1,7 +1,5 @@
 <template>
-  <div
-    class="scene-group"
-  >
+  <div class="scene-group">
     <div
       class="top-bar"
       :class="isConfirmingDeletion ? '' : 'show-icons-on-hover'"
@@ -18,13 +16,34 @@
       <div class="drag-image" ref="drag-image">
         <i class="iconfont icon-editor_folder_off"></i>
       </div>
-      <i class="iconfont icon-edit_input_arrow icon-expand" :class="isExpanded ? '' : 'collapsed'"></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>
+      <i
+        class="iconfont icon-edit_input_arrow icon-expand"
+        :class="isExpanded ? '' : 'collapsed'"
+      ></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="$i18n.t(`zh_key.${groupNode.name}`).indexOf('zh_key')>-1?groupNode.name:$i18n.t(`zh_key.${groupNode.name}`)">{{
-          $i18n.t(`zh_key.${groupNode.name}`).indexOf('zh_key')>-1?groupNode.name:$i18n.t(`zh_key.${groupNode.name}`)}}</span>
-        <i v-show="level === 1"
+        <span
+          class="group-name"
+          v-title="
+            $i18n.t(`zh_key.${groupNode.name}`).indexOf('zh_key') > -1
+              ? groupNode.name
+              : $i18n.t(`zh_key.${groupNode.name}`)
+          "
+          >{{
+            $i18n.t(`zh_key.${groupNode.name}`).indexOf("zh_key") > -1
+              ? groupNode.name
+              : $i18n.t(`zh_key.${groupNode.name}`)
+          }}</span
+        >
+        <i
+          v-show="level === 1"
           class="iconfont icon-editor_list_add icon-add"
           v-tooltip="$i18n.t('navigation.add_two_group')"
           @click.stop="onRequestForAddGroup"
@@ -32,20 +51,16 @@
         </i>
         <i
           class="iconfont icon-editor_list_image icon-image"
-          v-tooltip="$i18n.t('navigation.add_pano_or_scene')" 
+          v-tooltip="$i18n.t('navigation.add_pano_or_scene')"
           @click.stop="onRequestForAddScene"
           v-show="
             level === 2 ||
-            (
-              level === 1 &&
-              (
-                groupNode.children.length === 0 ||
-                (
-                  groupNode.children.length === 1 && 
-                  (groupNode.children[0].name === '默认二级分组'||groupNode.children[0].name === $i18n.t('navigation.default_group_two'))
-                )
-              )
-            )
+            (level === 1 &&
+              (groupNode.children.length === 0 ||
+                (groupNode.children.length === 1 &&
+                  (groupNode.children[0].name === '默认二级分组' ||
+                    groupNode.children[0].name ===
+                      $i18n.t('navigation.default_group_two')))))
           "
         >
         </i>
@@ -62,11 +77,13 @@
         >
         </i>
         <div class="deletion-confirm-wrap">
-          <div class="deletion-confirm" :class="isConfirmingDeletion ? 'show' : 'hide'"
+          <div
+            class="deletion-confirm"
+            :class="isConfirmingDeletion ? 'show' : 'hide'"
             v-clickoutside="onRequestForCancelDelete"
             @click.stop="onConfirmDelete"
           >
-           {{$i18n.t('navigation.delete')}} 
+            {{ $i18n.t("navigation.delete") }}
           </div>
         </div>
       </template>
@@ -84,8 +101,16 @@
     </div>
 
     <div class="group-content" v-if="isExpanded">
-      <template v-if="!(groupNode.children.length === 1 &&
-       (groupNode.children[0].name === '默认二级分组' || groupNode.children[0].name === $i18n.t('navigation.default_group_two')))">
+      <template
+        v-if="
+          !(
+            groupNode.children.length === 1 &&
+            (groupNode.children[0].name === '默认二级分组' ||
+              groupNode.children[0].name ===
+                $i18n.t('navigation.default_group_two'))
+          )
+        "
+      >
         <InsertPositionTip
           position-debug="1"
           :indentLevel="level + 1"
@@ -93,10 +118,7 @@
           :parentNode="groupNode"
           :index="0"
         ></InsertPositionTip>
-        <div
-          v-for="(item, index) of groupNode.children"
-          :key=item.id
-        >
+        <div v-for="(item, index) of groupNode.children" :key="item.id">
           <component
             :is="'SceneGroup'"
             ref="scene-group"
@@ -137,7 +159,7 @@
         ></InsertPositionTip>
         <div
           v-for="(item, index) of groupNode.children[0].children"
-          :key=item.id
+          :key="item.id"
         >
           <SceneInGroup
             :style="{
@@ -178,7 +200,7 @@ import InsertPositionTip from "@/components/insertPositionTipInEditor.vue";
 import { mapGetters, mapMutations } from "vuex";
 
 export default {
-  name: 'SceneGroup',
+  name: "SceneGroup",
   components: {
     SceneInGroup,
     MaterialSelector,
@@ -192,193 +214,208 @@ export default {
     level: {
       type: Number,
       default: 1,
-    }
+    },
   },
   data() {
     return {
       isExpanded: false,
       isRenaming: false,
-      newName: '',
+      newName: "",
       isConfirmingDeletion: false,
       isShowSelectionWindow: false,
       dragEnterTimerId: null,
-    }
+    };
   },
   computed: {
     ...mapGetters({
       info: "info",
-      dragInfo: 'editorNavDragInfo',
+      dragInfo: "editorNavDragInfo",
     }),
     topBarPaddingLeft() {
-      return 12 + (this.level - 1) * 12 + 'px' 
+      return 12 + (this.level - 1) * 12 + "px";
     },
     sceneItemPaddingLeft() {
-      return 18 + this.level * 12 + 'px' 
+      return 18 + this.level * 12 + "px";
     },
   },
   methods: {
     ...mapMutations({
-      recordDragType: 'setEditorNavDragType',
-      recordDragNode: 'setEditorNavDragNode',
-      clearDragInfo: 'clearEditorNavDragInfo',
+      recordDragType: "setEditorNavDragType",
+      recordDragNode: "setEditorNavDragNode",
+      clearDragInfo: "clearEditorNavDragInfo",
     }),
     onClickTopBar() {
       if (this.isConfirmingDeletion) {
-        return
+        return;
       }
-      this.isExpanded = !this.isExpanded
+      this.isExpanded = !this.isExpanded;
     },
 
     onRenameScene(...params) {
-      this.$emit('renameScene', ...params)
+      this.$emit("renameScene", ...params);
     },
     onDeleteScene(...params) {
-      this.$emit('deleteScene', ...params)
+      this.$emit("deleteScene", ...params);
     },
 
     onRequestForAddGroup() {
-      this.$emit('addGroup', this.groupNode.id)
+      this.$emit("addGroup", this.groupNode.id);
     },
     onRequestForAddScene() {
-      this.isShowSelectionWindow = true
+      this.isShowSelectionWindow = true;
     },
     onClickForRename() {
-      this.isRenaming = true
+      this.isRenaming = true;
       console.log(this.groupNode.name);
 
-      if (this.groupNode.name=='默认二级分组') {
-        this.newName = this.$i18n.t('navigation.default_group_two')
-      } else if (this.groupNode.name=='一级分组') {
-        this.newName = this.$i18n.t('navigation.group_one')
-      } else{
-        this.newName = this.groupNode.name
+      if (this.groupNode.name == "默认二级分组") {
+        this.newName = this.$i18n.t("navigation.default_group_two");
+      } else if (this.groupNode.name == "一级分组") {
+        this.newName = this.$i18n.t("navigation.group_one");
+      } else {
+        this.newName = this.groupNode.name;
       }
 
       this.$nextTick(() => {
         // this.$refs['input-for-rename'].focus()
-        this.$refs['input-for-rename'].select()
-        this.$refs['input-for-rename'].scrollIntoView({
-          behavior: 'smooth',
-        })
-      })
+        this.$refs["input-for-rename"].select();
+        this.$refs["input-for-rename"].scrollIntoView({
+          behavior: "smooth",
+        });
+      });
     },
     onInputNewNameComplete() {
-      this.isRenaming = false
+      this.isRenaming = false;
       console.log(this.groupNode.name);
       if (!this.newName.trim()) {
-        return 
+        return;
       }
       if (this.newName !== this.groupNode.name) {
-        this.$emit('renameGroup', this.groupNode.id, this.level, this.newName)
+        this.$emit("renameGroup", this.groupNode.id, this.level, this.newName);
       }
-      this.newName = ''
+      this.newName = "";
     },
     onInputEnter() {
-      this.isRenaming = false // 会导致input blur,进而触发onInputNewNameComplete
+      this.isRenaming = false; // 会导致input blur,进而触发onInputNewNameComplete
     },
     onInnerGroupRename(...params) {
-      this.$emit('renameGroup', ...params)
+      this.$emit("renameGroup", ...params);
     },
 
     onRequestForDelete() {
-      this.isConfirmingDeletion = true
+      this.isConfirmingDeletion = true;
     },
     onRequestForCancelDelete() {
       if (!this.isConfirmingDeletion) {
-        return
+        return;
       }
       // 先保持isConfirmingDeletion不变,因为onClickTopBar可能要用到
       setTimeout(() => {
-        this.isConfirmingDeletion = false
+        this.isConfirmingDeletion = false;
       }, 0);
     },
     onConfirmDelete() {
-      this.$emit('deleteGroup', this.groupNode.id, this.level)
-      this.isConfirmingDeletion = false
+      this.$emit("deleteGroup", this.groupNode.id, this.level);
+      this.isConfirmingDeletion = false;
     },
     onInnerGroupConfirmDelete(...params) {
-      this.$emit('deleteGroup', ...params)
+      this.$emit("deleteGroup", ...params);
     },
     onSubmitFromMaterialSelector(selected) {
-      let newScenes = []
+      let newScenes = [];
       for (const item of selected) {
-        if (item.materialType === 'pano') {
+        if (item.materialType === "pano") {
           newScenes.push({
             icon: item.icon,
             sceneCode: item.sceneCode,
             sceneTitle: item.name,
-            category: this.level === 1 ? this.groupNode.children[0].id : this.groupNode.id,
+            category:
+              this.level === 1
+                ? this.groupNode.children[0].id
+                : this.groupNode.id,
             type: "pano",
-            id: 's_' + this.$randomWord(true, 8, 8)
-          })
-        } else if (item.materialType === '3D') {
+            id: "s_" + this.$randomWord(true, 8, 8),
+          });
+        } else if (item.materialType === "3D") {
+          console.log("item.num", item.num);
           newScenes.push({
             icon: item.thumb,
             sceneCode: item.num,
             sceneTitle: item.sceneName,
-            category: this.level === 1 ? this.groupNode.children[0].id : this.groupNode.id,
+            category:
+              this.level === 1
+                ? this.groupNode.children[0].id
+                : this.groupNode.id,
             type: "4dkk",
-            version: item.buildType, // 'V3' OR 'V4'. 全景看看v1.3新增
-            id:'s_'+this.$randomWord(true,8,8)
-          })
+            version: item.isUpgrade === 1 ? "V4" : "V3", // 'V3' OR 'V4'. 全景看看v1.3新增
+            id: "s_" + this.$randomWord(true, 8, 8),
+          });
         }
       }
 
-      let allSuccess = true
+      let allSuccess = true;
       newScenes.forEach((item, i) => {
-        let temp = this.info.scenes.find(eachScene => {
-          return eachScene.sceneCode === item.sceneCode
-        })
+        let temp = this.info.scenes.find((eachScene) => {
+          return eachScene.sceneCode === item.sceneCode;
+        });
         if (temp) {
           setTimeout(() => {
             this.$msg.message(
-              `${item.type == '4dkk' ? this.$i18n.t('navigation.scene_name') : this.$i18n.t('navigation.pano')}${this.$i18n.t('navigation.already_exists',{msg:item.sceneTitle})}`)
-          }, i * 100)
-          allSuccess = false
-          return
+              `${
+                item.type == "4dkk"
+                  ? this.$i18n.t("navigation.scene_name")
+                  : this.$i18n.t("navigation.pano")
+              }${this.$i18n.t("navigation.already_exists", {
+                msg: item.sceneTitle,
+              })}`
+            );
+          }, i * 100);
+          allSuccess = false;
+          return;
         }
-        this.info.scenes.push(item)
-      })
+        this.info.scenes.push(item);
+      });
 
-      this.isShowSelectionWindow = false
+      this.isShowSelectionWindow = false;
       if (allSuccess) {
-        this.$msg.success(this.$i18n.t('gather.success'))
+        this.$msg.success(this.$i18n.t("gather.success"));
       }
     },
     onDragStart(e) {
       if (this.isRenaming) {
-        return
+        return;
       }
-      this.recordDragType(`topologyGroupLevel${this.level}`)
-      this.recordDragNode(this.groupNode)
-      e.dataTransfer.setDragImage(this.$refs['drag-image'], -10, -18)
+      this.recordDragType(`topologyGroupLevel${this.level}`);
+      this.recordDragNode(this.groupNode);
+      e.dataTransfer.setDragImage(this.$refs["drag-image"], -10, -18);
     },
     onDragEnter(e) {
-      if (e.target.contains(e.relatedTarget) || (this.level === 2 && this.dragInfo.type.includes('Group'))) {
-        return
+      if (
+        e.target.contains(e.relatedTarget) ||
+        (this.level === 2 && this.dragInfo.type.includes("Group"))
+      ) {
+        return;
       }
       this.dragEnterTimerId = setTimeout(() => {
         if (!this.isExpanded) {
-          this.isExpanded = true
+          this.isExpanded = true;
         }
-      }, 700)
+      }, 700);
     },
     onDragEnd() {
-      this.clearDragInfo()
-      clearTimeout(this.dragEnterTimerId)
+      this.clearDragInfo();
+      clearTimeout(this.dragEnterTimerId);
     },
     onDragLeave(e) {
       if (e.target.contains(e.relatedTarget)) {
-        return
+        return;
       }
-      clearTimeout(this.dragEnterTimerId)
-    }
-  },
-  mounted() {
+      clearTimeout(this.dragEnterTimerId);
+    },
   },
-  destroyed() {
-  }
-}
+  mounted() {},
+  destroyed() {},
+};
 </script>
 
 <style lang="less" scoped>
@@ -400,7 +437,10 @@ export default {
       }
     }
     &.show-icons-on-hover:hover {
-      > .icon-add, .icon-image, .icon-edit, .icon-delete {
+      > .icon-add,
+      .icon-image,
+      .icon-edit,
+      .icon-delete {
         display: block;
       }
     }
@@ -409,7 +449,7 @@ export default {
       width: 40px;
       height: 40px;
       background: #313131;
-      box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.5);
+      box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.5);
       border-radius: 4px;
       display: flex;
       justify-content: center;
@@ -491,7 +531,7 @@ export default {
         top: 0;
         bottom: 0;
         width: 100%;
-        background: #FA5555;
+        background: #fa5555;
         transition: right 0.3s;
         cursor: pointer;
         text-align: center;
@@ -499,7 +539,7 @@ export default {
         color: #fff;
         pointer-events: auto;
         &::after {
-          content: '';
+          content: "";
           height: 100%;
           vertical-align: middle;
           display: inline-block;
@@ -517,18 +557,18 @@ export default {
       flex: 1 1 auto;
       width: 1px;
       height: 30px;
-      background: #1A1B1D;
+      background: #1a1b1d;
       border-radius: 2px;
       border: 1px solid #404040;
       color: #fff;
       font-size: 14px;
       padding: 0 10px 0 16px;
       &:focus {
-        border-color: #0076F6;
+        border-color: #0076f6;
       }
     }
   }
   .group-content {
   }
 }
-</style>
+</style>

+ 69 - 49
packages/qjkankan-editor/src/components/sceneInGroupInEditor.vue

@@ -12,16 +12,21 @@
         alt=""
         class="scene-image"
         draggable="false"
-      >
+      />
     </div>
     <img
       :src="sceneInfo.icon + ossImagePreviewUrlSuffix()"
       alt=""
       class="scene-image"
       draggable="false"
-    >
+    />
     <div class="right">
-      <span v-if="!isRenaming" class="scene-title" v-title="sceneInfo.sceneTitle">{{sceneInfo.sceneTitle}}</span>
+      <span
+        v-if="!isRenaming"
+        class="scene-title"
+        v-title="sceneInfo.sceneTitle"
+        >{{ sceneInfo.sceneTitle }}</span
+      >
       <input
         v-if="isRenaming"
         class="scene-title-input"
@@ -33,13 +38,17 @@
         @keydown.enter="onInputEnter"
       />
       <div class="right-bottom">
-        <span class="scene-type">{{translateSceneType(sceneInfo.type)}}</span>
+        <span class="scene-type">{{ translateSceneType(sceneInfo.type) }}</span>
         <div class="icons">
-          <i class="iconfont icon-editor_list_edit icon-edit" v-tooltip="$i18n.t('navigation.rename')"
+          <i
+            class="iconfont icon-editor_list_edit icon-edit"
+            v-tooltip="$i18n.t('navigation.rename')"
             @click="onRequestForRename"
           >
           </i>
-          <i class="iconfont icon-editor_list_delete icon-delete" v-tooltip="$i18n.t('navigation.delete')"
+          <i
+            class="iconfont icon-editor_list_delete icon-delete"
+            v-tooltip="$i18n.t('navigation.delete')"
             @click="onRequestForDelete"
           >
           </i>
@@ -47,24 +56,26 @@
       </div>
     </div>
     <div class="deletion-confirm-wrap">
-      <div class="deletion-confirm" :class="isConfirmingDeletion ? 'show' : 'hide'"
+      <div
+        class="deletion-confirm"
+        :class="isConfirmingDeletion ? 'show' : 'hide'"
         v-clickoutside="onRequestForCancelDelete"
         @click="onConfirmDelete"
       >
-        {{$i18n.t('navigation.delete')}}
+        {{ $i18n.t("navigation.delete") }}
       </div>
     </div>
   </div>
 </template>
 
 <script>
-import { ossImagePreviewUrlSuffix } from '@/utils/other.js'
+import { ossImagePreviewUrlSuffix } from "@/utils/other.js";
 import { mapMutations } from "vuex";
+import { i18n } from "@/lang";
 
 export default {
-  name: 'SceneInGroupInEditor', 
-  components: {
-  },
+  name: "SceneInGroupInEditor",
+  components: {},
   props: {
     sceneInfo: {
       type: Object,
@@ -74,58 +85,67 @@ export default {
   data() {
     return {
       isRenaming: false,
-      newName: '',
+      newName: "",
       isConfirmingDeletion: false,
-    }
-  },
-  computed: {
+    };
   },
+  computed: {},
   methods: {
     ...mapMutations({
-      recordDragType: 'setEditorNavDragType',
-      recordDragNode: 'setEditorNavDragNode',
-      clearDragInfo: 'clearEditorNavDragInfo',
+      recordDragType: "setEditorNavDragType",
+      recordDragNode: "setEditorNavDragNode",
+      clearDragInfo: "clearEditorNavDragInfo",
     }),
     onDragStart(e) {
-      this.recordDragType('scene')
-      this.recordDragNode(this.sceneInfo)
-      e.dataTransfer.setDragImage(this.$refs['drag-image'], -10, -18)
+      this.recordDragType("scene");
+      this.recordDragNode(this.sceneInfo);
+      e.dataTransfer.setDragImage(this.$refs["drag-image"], -10, -18);
     },
     ossImagePreviewUrlSuffix,
     translateSceneType(type) {
-      if (type === 'pano') {
-        return this.$i18n.t('navigation.pano')
+      if (type === "pano") {
+        return this.$i18n.t("navigation.pano");
       } else {
-        return this.$i18n.t('navigation.scene')
+        return this.$i18n.t("navigation.scene");
       }
     },
     onRequestForRename() {
-      this.isRenaming = true
-      this.newName = this.sceneInfo.sceneTitle
+      this.isRenaming = true;
+      this.newName = this.sceneInfo.sceneTitle;
       this.$nextTick(() => {
-        this.$refs['input-for-rename'].focus()
-      })
+        this.$refs["input-for-rename"].focus();
+      });
     },
     onInputNewNameComplete() {
-      this.isRenaming = false
-      this.$emit('rename', this.sceneInfo.id, this.newName)
-      this.newName = ''
+      this.isRenaming = false;
+      if (
+        String(this.newName).trim().length === 0 ||
+        String(this.newName).trim().length > 50
+      ) {
+        this.$msg.warning(this.$i18n.t("hotspot.title_placeholder"));
+        return;
+      }
+
+      this.$emit("rename", this.sceneInfo.id, this.newName);
+      setTimeout(() => {
+        this.newName = "";
+      }, 100);
     },
     onInputEnter() {
-      this.isRenaming = false // 会导致input blur,进而触发onInputNewNameComplete
+      this.isRenaming = false; // 会导致input blur,进而触发onInputNewNameComplete
     },
     onRequestForDelete() {
-      this.isConfirmingDeletion = true
+      this.isConfirmingDeletion = true;
     },
     onRequestForCancelDelete() {
-      this.isConfirmingDeletion = false
+      this.isConfirmingDeletion = false;
     },
     onConfirmDelete() {
-      this.$emit('delete', this.sceneInfo.id)
-      this.isConfirmingDeletion = false
-    }
-  }
-}
+      this.$emit("delete", this.sceneInfo.id);
+      this.isConfirmingDeletion = false;
+    },
+  },
+};
 </script>
 
 <style lang="less" scoped>
@@ -152,7 +172,7 @@ export default {
     border-radius: 4px;
     padding: 4px;
     background: #313131;
-    box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.5);
+    box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.5);
     position: absolute;
     z-index: -1;
     img {
@@ -166,7 +186,7 @@ export default {
     flex: 0 0 auto;
     width: 64px;
     height: 64px;
-    background: #B0B0B0;
+    background: #b0b0b0;
     border-radius: 2px;
     object-fit: cover;
   }
@@ -188,14 +208,14 @@ export default {
     }
     .scene-title-input {
       height: 30px;
-      background: #1A1B1D;
+      background: #1a1b1d;
       border-radius: 2px;
       border: 1px solid #404040;
       color: #fff;
       font-size: 14px;
       padding: 0 10px 0 16px;
       &:focus {
-        border-color: #0076F6;
+        border-color: #0076f6;
       }
     }
     .right-bottom {
@@ -203,7 +223,7 @@ export default {
       justify-content: space-between;
       align-items: flex-end;
       .scene-type {
-        color: #0076F6;
+        color: #0076f6;
         line-height: 16px;
       }
       .icons {
@@ -215,7 +235,7 @@ export default {
         }
         .icon-edit {
           &:hover {
-            color: #0076F6;
+            color: #0076f6;
           }
         }
         .icon-delete {
@@ -242,7 +262,7 @@ export default {
       top: 0;
       bottom: 0;
       width: 100%;
-      background: #FA5555;
+      background: #fa5555;
       transition: right 0.3s;
       cursor: pointer;
       text-align: center;
@@ -250,7 +270,7 @@ export default {
       color: #fff;
       pointer-events: auto;
       &::after {
-        content: '';
+        content: "";
         height: 100%;
         vertical-align: middle;
         display: inline-block;
@@ -264,4 +284,4 @@ export default {
     }
   }
 }
-</style>
+</style>

+ 58 - 27
packages/qjkankan-editor/src/framework/MenuPC.vue

@@ -1,19 +1,50 @@
 <template>
-  <div class="pc-menu" :style="`width:${$i18n.t('style_key.menu_width')}`" app-border dir-right>
+  <div
+    class="pc-menu"
+    :style="`width:${$i18n.t('style_key.menu_width')}`"
+    app-border
+    dir-right
+  >
     <ul class="pc-menu-container">
-      <li v-for="(item, key) in menu" v-show="!item.hidden" :class="{disable:key!=0&&!isShow}" :key="key">
+      <li
+        v-for="(item, key) in menu"
+        v-show="!item.hidden"
+        :class="{ disable: (key != 0 && !isShow) || isEditing }"
+        :key="key"
+      >
         <router-link :to="item.link" :exact="false">
-          <img class="normal" :src="require(`@/assets/images/icons/navs/${item.icon}_normal.svg`)" alt="">
-          <img class="active" :src="require(`@/assets/images/icons/navs/${item.icon}_selected.svg`)" alt="">
+          <img
+            class="normal"
+            :src="require(`@/assets/images/icons/navs/${item.icon}_normal.svg`)"
+            alt=""
+          />
+          <img
+            class="active"
+            :src="
+              require(`@/assets/images/icons/navs/${item.icon}_selected.svg`)
+            "
+            alt=""
+          />
           <span>{{ item.text }}</span>
         </router-link>
       </li>
     </ul>
 
-    <a class="help" :href="$lang=='en'?'https://docs.4dkankan.com/#/product/4dpano/en-us/README':'https://docs.4dkankan.com/#/product/4dpano/zh-cn/README'" target="_blank">
-      <img v-tooltip="$i18n.t('edit_settings.help_center')"  :src="require(`@/assets/images/icons/help_tips.png`)" alt="">
+    <a
+      class="help"
+      :href="
+        $lang == 'en'
+          ? 'https://docs.4dkankan.com/#/product/4dpano/en-us/README'
+          : 'https://docs.4dkankan.com/#/product/4dpano/zh-cn/README'
+      "
+      target="_blank"
+    >
+      <img
+        v-tooltip="$i18n.t('edit_settings.help_center')"
+        :src="require(`@/assets/images/icons/help_tips.png`)"
+        alt=""
+      />
     </a>
-
   </div>
 </template>
 <script>
@@ -24,30 +55,31 @@ export default {
   name: "pc-menu",
   data() {
     return {
-      menu: []
+      menu: [],
     };
   },
   computed: {
     ...mapGetters({
-      isShow:'isShow'
-    })
+      isShow: "isShow",
+      isEditing: "isEditing",
+    }),
   },
-  watch:{
-    '$route.name':{
-      immediate:true,
-      handler:function (newVal) {
-        if (newVal!='base'&&!this.isShow) {
-          this.$router.push({path:'/base',redirect:true})
+  watch: {
+    "$route.name": {
+      immediate: true,
+      handler: function (newVal) {
+        if (newVal != "base" && !this.isShow) {
+          this.$router.push({ path: "/base", redirect: true });
         }
-      }
-    }
+      },
+    },
   },
   mounted() {
     // 添加滚动条
   },
   created() {
     this.menu = PCMenu;
-  }
+  },
 };
 </script>
 <style lang="less">
@@ -64,13 +96,13 @@ export default {
         height: 100%;
         padding: 10px 5px;
         display: inline-block;
-        >img{
+        > img {
           width: 18px;
         }
-        .normal{
+        .normal {
           display: inline-block;
         }
-        .active{
+        .active {
           display: none;
         }
         &.router-link-exact-active,
@@ -78,12 +110,11 @@ export default {
           color: @color;
           background: #252526;
 
-          .normal{
+          .normal {
             display: none;
           }
-          .active{
+          .active {
             display: inline-block;
-
           }
         }
       }
@@ -103,13 +134,13 @@ export default {
       font-size: 28px;
     }
   }
-  .help{
+  .help {
     position: absolute;
     bottom: 10px;
     left: 50%;
     width: 16px;
     transform: translateX(-50%);
-    >img{
+    > img {
       width: 100%;
     }
   }

+ 21 - 21
packages/qjkankan-editor/src/lang/_en.json

@@ -530,7 +530,7 @@
     "works": {
       "my": "My Project",
       "create": "Create a project",
-      "search": "Search",
+      "search": "Keywords",
       "preview": "View",
       "edit": "Edit",
       "share": "Share",
@@ -581,7 +581,7 @@
     "scene": "3D Scene",
     "siweikankan": "4DKanKan",
     "siweikanjian": "4DMinion",
-    "keywords": "Enter keywords",
+    "keywords": "keywords",
     "how_to_shoot": "How to shoot a 3D scene?",
     "pano_size": "Support 2:1 jpg files ≤ 120MB",
     "cancel": "Cancel",
@@ -597,16 +597,16 @@
     "audio_fail": "Format error. Support MP3 files: ≤ 20MB",
     "upload_material": "Upload materials",
     "new_folder": "New Folder",
-    "new_folder_placeholder": "Please enter a folder name up to 15 characters in length",
+    "new_folder_placeholder": "Please enter",
     "folder_name_already_used": "Folder already exists",
     "move_folder": "Move",
     "move_folder_to": "Move to",
     "no_folder_need_create": "Please create a folder first",
-    "rename_folder_placeholder": "Please enter a folder name up to 15 characters in length",
+    "rename_folder_placeholder": "Please enter",
     "video_size": "Support MP4 files: ≤ 200MB",
     "video_limit": "The file is too large.Support MP4 files: ≤ 200MB",
     "video_fail": "Format error. Support MP4 files: ≤ 200MB",
-    "serch_material": "Search",
+    "serch_material": "Keywords",
     "rename": "Rename",
     "delete": "Delete",
     "no_serch_result": "No results found",
@@ -645,7 +645,7 @@
     "nothing_edit": "You haven't created any content yet",
     "at_least_one_scene": "At least one scene can be previewed. Please go to \"Scene Navigation\" to add",
     "exitVr": "Exit VR",
-    "dir": "目录",
+    "dir": "Directory",
     "root_dir": "Root Directory",
     "no_more_data": "no more results.",
     "converinfo_no_valid": "Please fill out the content for the opening cover."
@@ -758,7 +758,7 @@
     "水晶球开场": "Start with crystal ball",
     "开场提示": "Notifications",
     "开场动画": "Animations",
-    "访问密码": "Access code",
+    "访问密码": "Access Code",
     "自动巡游": "Rotation",
     "背景音乐": "BGM",
     "自定义LOGO": "Custom Logo",
@@ -792,9 +792,9 @@
     "group_one": "1st Grouping",
     "group_two": "2nd Grouping",
     "default_group_two": "Default as 2nd grouping",
-    "init_scene": "Start screen",
-    "setting_init_scene": "Start screen settings",
-    "init_scene_tips": "The start screen is the initial scene entered when a link is viewed, and it is not fixed to a specific scene when \n is not set.",
+    "init_scene": "Initial Scene",
+    "setting_init_scene": "Initial scene settings",
+    "init_scene_tips": "The initial scene is the enter screen when a link is viewed, and it will not applied to a specific scene when \n is not set.",
     "edit_init_scene": "Edit",
     "delete_init_scene": "Delete",
     "keep_one_scene": "Please retain at least one scene",
@@ -808,7 +808,7 @@
     "already_exists": "{msg} already exists, can not be repeatedly added"
   },
   "screen": {
-    "init_screen": "Start screen",
+    "init_screen": "Start Screen",
     "screen_tips": "The start screen is the initial screen that appears when entering a scene; please drag the panorama to select the appropriate screen setting.",
     "setting_screen": "Set the current view to the start screen",
     "goto_4dkk_edit_tips": "4Dage Personal Center~"
@@ -819,7 +819,7 @@
     "img_size":"Upload up to 20 images",
     "hotspot_tips": "Add icon hotspots to the panorama and configure their effect",
     "add_hotspot": "Add hotspot",
-    "current_hotspots": "Current panorama hotspots",
+    "current_hotspots": "Current Pano Hotspots",
     "delete": "Delete",
     "add": "Add",
     "edit": "Edit",
@@ -832,7 +832,7 @@
     "hotspot_icon_type": {
       "system_icon": "Default icon",
       "custom_image": "Custom images",
-      "serial_frame": "Sequential Frames",
+      "serial_frame": "Sequential frames",
       "personalized_tag": "Custom labels"
     },
     "add_icon": "Add Icon",
@@ -840,11 +840,11 @@
     "add_serial_frame_rule": "Maximum width: 300 pixels, unlimited height",
     "frame_total_number": "Total Frames",
     "frame_duration": "Total Play Time",
-    "select_icon": "Choose Icon",
-    "if_show_marking_line": "Display dimension line or not",
-    "shape_filling_color": "Shape Fill",
-    "shape_border_color": "Stroke",
-    "text_color": "Color",
+    "select_icon": "Change",
+    "if_show_marking_line": "Display dimension line",
+    "shape_filling_color": "Shape Color",
+    "shape_border_color": "Shape Stroke",
+    "text_color": "Text Color",
     "text_direction": "文字排序",
     "left_to_right": "从左到右",
     "top_to_down": "从上到下",
@@ -862,7 +862,7 @@
     "title_left": "Left",
     "title_right": "Right",
     "title_custom": "自定义拖动标题",
-    "title_placeholder": "Enter a title with a maximum of 15 characters",
+    "title_placeholder": "Enter a title",
     "effect_settings": "Effect settings",
     "cancel": "Cancel",
     "finish": "Finish",
@@ -906,10 +906,10 @@
     "add_video": "Add a video",
     "select_video": "Add a video",
     "change_video": "Change a video",
-    "MB_limit": "Undering {value}MB",
+    "MB_limit": "Within {value}MB",
     "text_content": "Text",
     "apply_to_all": "应用到所有",
-    "phone_placeholder": "Please enter the telephone number",
+    "phone_placeholder": "Please enter",
     "phone_error_tip": "Please enter the correct telephone number",
     "select_pdf": "Add a PDF",
     "change_pdf": "Change the PDF",

+ 11 - 10
packages/qjkankan-editor/src/views/hotspot/EditPanel.vue

@@ -338,12 +338,12 @@ export default {
     },
     currentTitleDispayModeIdx() {
       switch (this.hotspot.titleDisplayMode) {
-        case "hover":
-          return 0;
+        // case "hover":
+        //   return 0;
         case "always":
-          return 1;
+          return 0;
         case "never":
-          return 2;
+          return 1;
         default:
           return 0;
       }
@@ -405,11 +405,12 @@ export default {
           break;
         case "imageText":
           if (
-            this.hotspot.imageTextInfo.imageList.length === 0 &&
-            !this.hotspot.imageTextInfo.text
+            this.hotspot.imageTextInfo.imageList.length === 0 ||
+            this.hotspot.imageTextInfo.text.length === 0
           ) {
             return false;
           }
+
           break;
         case "article":
           if (!this.hotspot.articleInfo.html) {
@@ -560,13 +561,13 @@ export default {
     },
     onSelectTitleDisplayMode(idx) {
       switch (idx) {
+        // case 0:
+        //   this.hotspot.titleDisplayMode = "hover";
+        //   break;
         case 0:
-          this.hotspot.titleDisplayMode = "hover";
-          break;
-        case 1:
           this.hotspot.titleDisplayMode = "always";
           break;
-        case 2:
+        case 1:
           this.hotspot.titleDisplayMode = "never";
           break;
         default:

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

@@ -22,6 +22,7 @@
             })
           "
         >
+       
           <img class="icon" :src="item.icon" alt="" draggable="false" />
           <div class="type-name">{{ item.name }}</div>
           <img

+ 85 - 57
packages/qjkankan-editor/src/views/hotspot/hotspotType/imageText.vue

@@ -1,34 +1,43 @@
 <template>
   <div class="image-text-effect-setting">
-    
     <div class="image-list-wrap">
       <button
         class="add-btn"
         v-if="hotspot.imageTextInfo.imageList.length === 0"
         @click="isShowImageSelect = true"
       >
-        <img src="@/assets/images/default/hotspot_scene_add.png" alt="">
-        <div class="name">{{$i18n.t('hotspot.add_image')}}</div>
-        <div class="tip">{{$i18n.t('hotspot.MB_limit', {value: '10'})}}</div>
+        <img src="@/assets/images/default/hotspot_scene_add.png" alt="" />
+        <div class="name">{{ $i18n.t("hotspot.add_image") }}</div>
+        <div class="tip">
+          {{ $i18n.t("hotspot.MB_limit", { value: "10" }) }}
+        </div>
       </button>
       <ul class="image-list" v-else>
         <button class="add-btn" @click="isShowImageSelect = true">
           <div class="inner-wrap">
-            <img src="@/assets/images/default/hotspot_scene_add.png" alt="">
-            <div>{{$i18n.t('hotspot.add_tooltips')}}</div>
+            <img src="@/assets/images/default/hotspot_scene_add.png" alt="" />
+            <div>{{ $i18n.t("hotspot.add_tooltips") }}</div>
           </div>
         </button>
-        <li v-for="(item,i) in hotspot.imageTextInfo.imageList" :key="i">
-          <img class="thumb" :src="item.icon || $thumb" alt="">
+        <li v-for="(item, i) in hotspot.imageTextInfo.imageList" :key="i">
+          <img class="thumb" :src="item.icon || $thumb" alt="" />
           <button class="delete-btn" @click="del(item)">
-            <img class="normal" src="@/assets/images/icons/close01_normal@2x.png" alt="">
-            <img class="hover" src="@/assets/images/icons/close01_hover@2x.png" alt="">
+            <img
+              class="normal"
+              src="@/assets/images/icons/close01_normal@2x.png"
+              alt=""
+            />
+            <img
+              class="hover"
+              src="@/assets/images/icons/close01_hover@2x.png"
+              alt=""
+            />
           </button>
         </li>
       </ul>
     </div>
 
-    <div class="remark">{{$i18n.t('hotspot.text_content')}}</div>
+    <div class="remark">{{ $i18n.t("hotspot.text_content") }}</div>
     <div class="textarea-wrapper">
       <!-- <textarea
         v-model.trim="text"
@@ -43,7 +52,7 @@
         :maxlength="500"
         @change="onEditorChange"
       />
-      <span class="count">{{textLength}}/500</span>
+      <span class="count">{{ textLength }}/500</span>
     </div>
 
     <!-- <div class="switcher-wrap">
@@ -53,22 +62,39 @@
         @change="onSwitcherChange"
       />
     </div> -->
-    
-    <div class="remark">{{$i18n.t('hotspot.add_audio')}}</div>
-    <button class="add-btn" v-if="!hotspot.imageTextInfo.audio.id" @click="isShowAudioSelect = true">
+
+    <div class="remark">{{ $i18n.t("hotspot.add_audio") }}</div>
+    <button
+      class="add-btn"
+      v-if="!hotspot.imageTextInfo.audio.id"
+      @click="isShowAudioSelect = true"
+    >
       <i class="iconfont icon-editor_add"></i>
-      {{$i18n.t('hotspot.add_audio')}}
+      {{ $i18n.t("hotspot.add_audio") }}
     </button>
     <template v-else>
       <div class="music-display" @click.self="onClickCurrentMusic">
-        <Audio ref="my-audio" class="audio-control" :backgroundColor="'#1A1B1D'" :myAudioUrl="hotspot.imageTextInfo.audio.ossPath"></Audio>
-        <div class="name" v-title="hotspot.imageTextInfo.audio.name" @click="onClickCurrentMusic">{{hotspot.imageTextInfo.audio.name}}</div>
-        <i class="iconfont icon-editor_list_delete" @click.stop="hotspot.imageTextInfo.audio = {}"></i>
+        <Audio
+          ref="my-audio"
+          class="audio-control"
+          :backgroundColor="'#1A1B1D'"
+          :myAudioUrl="hotspot.imageTextInfo.audio.ossPath"
+        ></Audio>
+        <div
+          class="name"
+          v-title="hotspot.imageTextInfo.audio.name"
+          @click="onClickCurrentMusic"
+        >
+          {{ hotspot.imageTextInfo.audio.name }}
+        </div>
+        <i
+          class="iconfont icon-editor_list_delete"
+          @click.stop="hotspot.imageTextInfo.audio = {}"
+        ></i>
       </div>
       <button class="change-btn" @click="isShowImageSelect = true">
         <i class="iconfont icon-editor_update"></i>
-      {{$i18n.t('hotspot.change_audio')}}
-        
+        {{ $i18n.t("hotspot.change_audio") }}
       </button>
     </template>
 
@@ -91,7 +117,6 @@
         initialMaterialType="audio"
       />
     </div>
-
   </div>
 </template>
 
@@ -99,63 +124,66 @@
 import { mapGetters } from "vuex";
 
 import MaterialSelector from "@/components/materialSelector.vue";
-import Editor from "@/components/shared/Editor"
+import Editor from "@/components/shared/Editor";
 import Switcher from "@/components/shared/Switcher.vue";
 import Audio from "@/components/audio/audioButton.vue";
 
 export default {
-  components:{
+  components: {
     MaterialSelector,
     Editor,
     Switcher,
     Audio,
   },
-  data(){
+  data() {
     return {
       isShowImageSelect: false,
       textLength: 0,
       isShowAudioSelect: false,
-    }
+    };
   },
   computed: {
     ...mapGetters({
-      hotspot: 'hotspot',
+      hotspot: "hotspot",
     }),
   },
-  methods:{
-    del(item){
-      let index = this.hotspot.imageTextInfo.imageList.findIndex(i => i.id === item.id)
-      ~index && this.hotspot.imageTextInfo.imageList.splice(index, 1)
+  methods: {
+    del(item) {
+      let index = this.hotspot.imageTextInfo.imageList.findIndex(
+        (i) => i.id === item.id
+      );
+      ~index && this.hotspot.imageTextInfo.imageList.splice(index, 1);
     },
     onImageSelected(data) {
-      this.hotspot.imageTextInfo.imageList = this.hotspot.imageTextInfo.imageList.concat(data)
+      this.hotspot.imageTextInfo.imageList =
+        this.hotspot.imageTextInfo.imageList.concat(data);
       if (this.hotspot.imageTextInfo.imageList.length > 20) {
         this.$alert({ content: this.$i18n.t("hotspot.img_size") });
         this.hotspot.imageTextInfo.imageList.length = 20;
       }
-      this.isShowImageSelect = false
+      this.isShowImageSelect = false;
     },
     onEditorChange(content) {
-      this.textLength = content.size || 0
-    //  console.log('content',content);
-     this.hotspot.imageTextInfo.text = content.html;
+      this.textLength = content.size || 0;
+      //  console.log('content',content);
+      this.hotspot.imageTextInfo.text = content.html;
     },
     onSwitcherChange(v) {
-      this.hotspot.imageTextInfo.isApplyToAll = v
+      this.hotspot.imageTextInfo.isApplyToAll = v;
     },
     onClickCurrentMusic() {
-      if (this.$refs['my-audio']) {
-        this.$refs['my-audio'].switchPlayPause()
+      if (this.$refs["my-audio"]) {
+        this.$refs["my-audio"].switchPlayPause();
       }
     },
 
-    onAudioSelected(data){
-      console.log('sadf', data);
-      this.hotspot.imageTextInfo.audio = {...data[0]}
-      this.isShowAudioSelect = false
+    onAudioSelected(data) {
+      console.log("sadf", data);
+      this.hotspot.imageTextInfo.audio = { ...data[0] };
+      this.isShowAudioSelect = false;
     },
   },
-}
+};
 </script>
 
 <style lang="less" scoped>
@@ -165,10 +193,10 @@ export default {
     font-size: 14px;
     color: #ababab;
   }
-    
+
   > .image-list-wrap {
     min-height: 242px;
-    background: #1A1B1D;
+    background: #1a1b1d;
     border-radius: 2px;
     border: 1px solid #404040;
     position: relative;
@@ -192,7 +220,7 @@ export default {
       > .tip {
         margin-top: 4px;
         font-size: 12px;
-        color: #FFFFFF;
+        color: #ffffff;
         opacity: 0.2;
       }
     }
@@ -202,7 +230,7 @@ export default {
       > .add-btn {
         background: none;
         border-radius: 2px;
-        border: 2px solid #0076F6;
+        border: 2px solid #0076f6;
         color: @color;
         cursor: pointer;
         display: inline-block;
@@ -276,13 +304,13 @@ export default {
     margin-top: 16px;
     position: relative;
     border: 1px solid rgba(151, 151, 151, 0.2);
-    background: #1A1B1D;
+    background: #1a1b1d;
     border-radius: 2px;
     height: 200px;
     width: 100%;
 
     &:focus-within {
-      border-color: #0076F6;
+      border-color: #0076f6;
     }
 
     > textarea {
@@ -321,11 +349,11 @@ export default {
     margin-top: 16px;
     width: 100%;
     height: 40px;
-    background: #1A1B1D;
+    background: #1a1b1d;
     border-radius: 2px;
     border: 1px solid #404040;
     display: block;
-    color: #0076F6;
+    color: #0076f6;
     font-size: 14px;
     cursor: pointer;
     &:hover {
@@ -340,7 +368,7 @@ export default {
     margin-top: 16px;
     width: 100%;
     height: 40px;
-    background: #1A1B1D;
+    background: #1a1b1d;
     border-radius: 2px;
     border: 1px solid #404040;
     color: #fff;
@@ -348,7 +376,7 @@ export default {
     font-size: 14px;
     position: relative;
     &:hover {
-      color: #0076F6;
+      color: #0076f6;
       border-color: @color;
       > .audio-control {
         display: inline-block;
@@ -382,7 +410,7 @@ export default {
       transform: translateY(-50%);
       right: 18px;
       &:hover {
-        color: #FA5555;
+        color: #fa5555;
       }
     }
   }
@@ -390,11 +418,11 @@ export default {
     margin-top: 16px;
     width: 100%;
     height: 40px;
-    background: #1A1B1D;
+    background: #1a1b1d;
     border-radius: 2px;
     border: 1px solid #404040;
     display: block;
-    color: #0076F6;
+    color: #0076f6;
     font-size: 14px;
     cursor: pointer;
     &:hover {

+ 3 - 0
packages/qjkankan-editor/src/views/material/audio/index.vue

@@ -514,11 +514,14 @@ export default {
       e.files.forEach((eachFile, i) => {
         console.log(
           "check-audio-1",
+          eachFile.name,
           eachFile.name.toLowerCase().indexOf("mp3")
         );
         console.log(
           "check-audio-2",
+          eachFile.type,
           eachFile.type.toLowerCase().indexOf("mp3")
+   
         );
         if (
           eachFile.name.toLowerCase().indexOf("mp3") <= -1 ||

+ 3 - 3
packages/qjkankan-kankan-view/src/app.js

@@ -13,9 +13,10 @@ export function createApp(opitons = {}, forceNew = false) {
         target: 'self',
         onAction: function (url) {
             const newUrl = new URL(url);
-            const isV3 = newUrl.pathname.indexOf('spc.html') >= -1 ;
+            const isV4 = newUrl.pathname.indexOf('spg.html') > -1;
+            console.log('场景原Link:', url, isV4);
             let result
-            if (!isV3) {
+            if (isV4) {
                 const newPathname = '/panorama' + newUrl.pathname;
                 result = newUrl.origin + newPathname + newUrl.search;
                 // var result = newUrl.protocol + part1 + '/panorama/' + part2;
@@ -24,7 +25,6 @@ export function createApp(opitons = {}, forceNew = false) {
                 result = url
                 console.log('场景V3Link:', result);
             }
-
             return result
         }
     }

+ 1 - 0
packages/qjkankan-view/src/components/assembly/OpeningMobile.vue

@@ -454,6 +454,7 @@ onMounted(() => {
 
   .contain {
     height: 100%;
+    object-fit: contain;
   }
 
   .cover {

+ 8 - 4
packages/qjkankan-view/src/components/assembly/Tags/metas/metas-imagetext.vue

@@ -283,21 +283,24 @@ watchEffect(() => {
 
   .main-text-container {
     width: 100%;
-    height: 550px;
+    height: 750px;
     // max-width: 1920px;
     // max-width: 1564px;
     display: flex;
-    background: rgba(0, 0, 0, 0.8);
+
     .image-left {
-      flex: 1 1 58%;
+      flex: 1 1 76.8%;;
+      
       overflow: hidden;
       position: relative;
+      background: rgba(0, 0, 0, 1);
     }
     .text-right {
-      flex: 0 0 32%;
+      flex: 0 0 23.2%;
       overflow: hidden;
       color: white;
       overflow-y: scroll;
+      background-color: rgba(0, 0, 0, 0.80);
       .txtbody {
         display: block;
         word-wrap: break-word;
@@ -525,6 +528,7 @@ watchEffect(() => {
 @media only screen and (max-width: 1440px) {
   .imagetxtcon .main-text-container {
     max-width: 1060px;
+    height: 500px;
   }
 }
 @media only screen and (min-width: 1440px) {