jinx 11 月之前
父節點
當前提交
d037cf4e6b
共有 37 個文件被更改,包括 1367 次插入691 次删除
  1. 18 0
      packages/qjkankan-editor/public/static/template/customTooltip.xml
  2. 37 37
      packages/qjkankan-editor/src/Store/index.js
  3. 157 133
      packages/qjkankan-editor/src/Store/modules/base.js
  4. 55 12
      packages/qjkankan-editor/src/Store/modules/explanation.js
  5. 250 11
      packages/qjkankan-editor/src/Store/modules/hotspot.js
  6. 81 14
      packages/qjkankan-editor/src/Store/modules/mask.js
  7. 55 31
      packages/qjkankan-editor/src/Store/modules/navigation.js
  8. 10 1
      packages/qjkankan-editor/src/Store/modules/scene.js
  9. 86 14
      packages/qjkankan-editor/src/Store/modules/screen.js
  10. 1 1
      packages/qjkankan-editor/src/Store/modules/tags.js
  11. 30 7
      packages/qjkankan-editor/src/components/dragTree/index.vue
  12. 10 13
      packages/qjkankan-editor/src/core/hotspot.js
  13. 18 19
      packages/qjkankan-editor/src/core/utils.js
  14. 50 2
      packages/qjkankan-editor/src/framework/EditorHead.vue
  15. 2 6
      packages/qjkankan-editor/src/framework/core/index.vue
  16. 15 3
      packages/qjkankan-editor/src/framework/play/pano/components/new-list.vue
  17. 15 9
      packages/qjkankan-editor/src/framework/play/pano/index.vue
  18. 1 1
      packages/qjkankan-editor/src/framework/show/index.vue
  19. 1 1
      packages/qjkankan-editor/src/framework/showMobile/index.vue
  20. 5 4
      packages/qjkankan-editor/src/pages/Edit.vue
  21. 203 112
      packages/qjkankan-editor/src/utils/other.js
  22. 24 66
      packages/qjkankan-editor/src/views/base/Toolbar.vue
  23. 12 25
      packages/qjkankan-editor/src/views/base/index.vue
  24. 11 3
      packages/qjkankan-editor/src/views/explanation/explanationSettings.vue
  25. 45 101
      packages/qjkankan-editor/src/views/hotspot/EditPanel.vue
  26. 133 48
      packages/qjkankan-editor/src/views/hotspot/HotSpotList.vue
  27. 1 1
      packages/qjkankan-editor/src/views/hotspot/hotspotIconType/custom_image.vue
  28. 1 1
      packages/qjkankan-editor/src/views/hotspot/hotspotIconType/personalized_tag.vue
  29. 1 1
      packages/qjkankan-editor/src/views/hotspot/hotspotIconType/serial_frame.vue
  30. 1 1
      packages/qjkankan-editor/src/views/hotspot/hotspotIconType/system_icon.vue
  31. 1 1
      packages/qjkankan-editor/src/views/hotspot/hotspotType/imageText.vue
  32. 1 1
      packages/qjkankan-editor/src/views/hotspot/hotspotType/pdf.vue
  33. 1 1
      packages/qjkankan-editor/src/views/hotspot/hotspotType/phone.vue
  34. 12 2
      packages/qjkankan-editor/src/views/mask/setting.vue
  35. 8 3
      packages/qjkankan-editor/src/views/navigation/groupSettings.vue
  36. 1 1
      packages/qjkankan-editor/src/views/navigation/initialSceneSettings.vue
  37. 14 4
      packages/qjkankan-editor/src/views/screen/Setting.vue

+ 18 - 0
packages/qjkankan-editor/public/static/template/customTooltip.xml

@@ -2,6 +2,17 @@
     <!-- 1.20. 新热点模式 -->
     <action name="addJQHotspot">
         <!-- showlog(); -->
+        trace('pramas1::',%1);
+        trace('pramas2::',%2);
+        trace('pramas3::',%3);
+        trace('pramas4::',%4);
+        trace('pramas5::',%5);
+        trace('pramas6::',%6);
+        trace('pramas7::',%7);
+        trace('pramas8::',%8);
+        trace('pramas9::',%9);
+        trace('pramas10::',%10);
+     
         set(hsp_name,%1); 
         set(hsp_type,%2); 
         txtadd(iconUrl,'',%4);
@@ -392,9 +403,16 @@
             add(lastPy,dpy,5);
             trace('dpy::',dpy);
             mul(lastPy, -1);
+         
             set(layer[get(posName)].align,center);
             set(layer[get(posName)].y,get(lastPy));
             set(layer[get(posName)].x,0);
+            if(isNaN(dpy),
+              trace('lastPy::',get(lastPy));
+              set(layer[get(posName)].y,-40);
+            )
+
+        
         );
          if(
             pos == 'bottom',

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

@@ -15,7 +15,7 @@ const store = new Vuex.Store({
     info: "",
     infoSnapshotAtSave: "",
     showInfo: "",
-    hotspot: "", // 当前在新增或编辑的热点的信息
+    // hotspot: "", // 当前在新增或编辑的热点的信息
     backupHotSpot: "",
     initScene: "",
     tablist: [],
@@ -96,7 +96,7 @@ const store = new Vuex.Store({
       return !isSameObject(state.info, state.infoSnapshotAtSave);
     },
     showInfo: (state) => state.showInfo,
-    hotspot: (state) => state.hotspot,
+    // hotspot: (state) => state.hotspot,
     backupHotSpot: (state) => state.backupHotSpot,
     initScene: (state) => state.initScene,
     activeItem: (state) => state.activeItem,
@@ -114,37 +114,37 @@ const store = new Vuex.Store({
     editorNavDragInfo: (state) => state.editorNavDragInfo,
 
     // 1.3.0 新增层级后所有热点类型不同汇总显示的ICON
-    hotspotIcon: (state) => {
-      const category = state.hotspot && state.hotspot.hotspotIconType ? state.hotspot.hotspotIconType : "";
-      switch (category) {
-        case "system_icon":
-          return {
-            img: state.hotspot.img,
-            type: "system_icon",
-          };
-        case "custom_image":
-          return {
-            ...state.hotspot.customIconInfo,
-            type: "custom_image",
-          };
-        case "serial_frame":
-          return {
-            ...state.hotspot.serialFrameInfo,
-            img: state.hotspot.serialFrameInfo.img,
-            type: "serial_frame",
-          };
-        case "personalized_tag":
-          return {
-            ...state.hotspot.personalizedTagInfo,
-            img: "",
-            type: "personalized_tag",
-          };
-        default:
-          return {
-            img: "",
-          };
-      }
-    },
+    // hotspotIcon: (state) => {
+    //   const category = state.hotspot && state.hotspot.hotspotIconType ? state.hotspot.hotspotIconType : "";
+    //   switch (category) {
+    //     case "system_icon":
+    //       return {
+    //         img: state.hotspot.img,
+    //         type: "system_icon",
+    //       };
+    //     case "custom_image":
+    //       return {
+    //         ...state.hotspot.customIconInfo,
+    //         type: "custom_image",
+    //       };
+    //     case "serial_frame":
+    //       return {
+    //         ...state.hotspot.serialFrameInfo,
+    //         img: state.hotspot.serialFrameInfo.img,
+    //         type: "serial_frame",
+    //       };
+    //     case "personalized_tag":
+    //       return {
+    //         ...state.hotspot.personalizedTagInfo,
+    //         img: "",
+    //         type: "personalized_tag",
+    //       };
+    //     default:
+    //       return {
+    //         img: "",
+    //       };
+    //   }
+    // },
   },
   mutations: {
     SetUserAvatar(state, avatar) {
@@ -192,10 +192,10 @@ const store = new Vuex.Store({
     TakeInfoSnapShotAtSave(state) {
       state.infoSnapshotAtSave = deepClone(state.info);
     },
-    SetHotspot(state, data) {
-      state.hotspot = data;
-      this.commit("BackupHotSpot", browser.CloneObject(data));
-    },
+    // SetHotspot(state, data) {
+    //   state.hotspot = data;
+    //   this.commit("BackupHotSpot", browser.CloneObject(data));
+    // },
     BackupHotSpot(state, data) {
       state.backupHotSpot = data;
     },

+ 157 - 133
packages/qjkankan-editor/src/Store/modules/base.js

@@ -32,148 +32,169 @@ export default {
           }
         });
       }
+      // console.error("11111", state.sceneList);
+      // if (rootState.scene.currentScene) {
+      //   let currentScene = state.sceneList.find((item) => item.id == rootState.scene.currentScene.id || item.sid == rootState.scene.currentScene.id);
+      //   if (currentScene) {
+      //     this.commit("scene/setCurrentScene", currentScene);
+      //   }
+      // }
       return state.baseInfo;
     },
   },
   mutations: {
     ininDefaultData(state, payload) {
       let forArr = ["workCustomMaskList", "workVisualAngleList", "workExplanationList"];
-      if (state.sceneList.length) {
-        state.sceneList.forEach((item, index) => {
-          forArr.map((key) => {
-            let obj = {};
-            state.baseInfo[key].forEach((key_item, key_index) => {
-              if (key == "workVisualAngleList" && item.id == key_item.navigationId) {
-                key_item.icon = item.icon;
-              }
-              obj[key_item.navigationId] = key_item;
-            });
+      // state.baseInfo.workVisualAngleList.forEach((item, index) => {
+      //   if (!state.sceneList.some((j_item) => item.navigationId == j_item.id || item.navigationId == j_item.sid)) {
+      //     console.error(index, "删除了");
+      //     state.baseInfo.workVisualAngleList.splice(index, 1);
+      //   }
+      // });
+      // setTimeout(() => {
+      console.error(state.sceneList);
+      this.commit("screen/setVisualAngleList", { sceneList: state.sceneList, workVisualAngleList: state.baseInfo.workVisualAngleList });
+      this.commit("mask/setCustomMaskList", { sceneList: state.sceneList, workCustomMaskList: state.baseInfo.workCustomMaskList, workId: state.baseInfo.workId });
+      this.commit("explanation/setExplanationList", { sceneList: state.sceneList, workExplanationList: state.baseInfo.workExplanationList });
+      // }, 0);
+      // if (state.sceneList.length) {
+      //   state.sceneList.forEach((item, index) => {
+      //     forArr.map((key) => {
+      //       let obj = {};
+      //       state.baseInfo[key].forEach((key_item, key_index) => {
+      //         if (key == "workVisualAngleList" && item.id == key_item.navigationId || item.sid == key_item.navigationId ) {
+      //           key_item.icon = item.icon;
+      //         }
+      //         obj[key_item.navigationId] = key_item;
+      //       });
 
-            if (obj[item.id]) {
-            } else {
-              switch (key) {
-                case "workCustomMaskList":
-                  console.error("workCustomMaskList");
-                  state.baseInfo[key].push({
-                    data: {
-                      earth: {
-                        antidistorted: true,
-                        fodderId: null,
-                        icon: "",
-                        isDelete: 0,
-                        isShow: false,
-                        navigationId: item.id,
-                        scale: 1,
-                        type: "earth",
-                        workId: state.baseInfo.workId,
-                      },
-                      sky: {
-                        antidistorted: true,
-                        fodderId: null,
-                        icon: "",
-                        isDelete: 0,
-                        isShow: true,
-                        navigationId: item.id,
-                        scale: 1,
-                        type: "sky",
-                        workId: state.baseInfo.workId,
-                      },
-                    },
-                    navigationId: item.id,
-                  });
-                  break;
-                case "workVisualAngleList":
-                  state.baseInfo[key].push({
-                    hlookat: 0,
-                    icon: item.icon,
-                    // id: 0,
-                    vlookat: 0,
-                    vlookatmax: 90,
-                    vlookatmin: -90,
-                    workId: state.baseInfo.workId,
-                    navigationId: item.id,
-                  });
-                  break;
-                case "workExplanationList":
-                  console.error("workExplanationList");
-                  state.baseInfo[key].push({
-                    fodderId: null,
-                    audioName: "",
-                    audioUrl: "",
-                    openByDefault: true,
-                    navigationId: item.id,
-                    playRepeat: true,
-                  });
-                  break;
-              }
-            }
+      //       if (obj[item.id]) {
+      //         console.error(key,1);
+      //       } else {
+      //         console.error(key,2);
+      //         switch (key) {
+      //           case "workCustomMaskList":
+      //             console.error("workCustomMaskList");
+      //             state.baseInfo[key].push({
+      //               data: {
+      //                 earth: {
+      //                   antidistorted: true,
+      //                   fodderId: null,
+      //                   icon: "",
+      //                   isDelete: 0,
+      //                   isShow: false,
+      //                   navigationId: item.sid ? item.sid : item.id,
+      //                   scale: 1,
+      //                   type: "earth",
+      //                   workId: state.baseInfo.workId,
+      //                 },
+      //                 sky: {
+      //                   antidistorted: true,
+      //                   fodderId: null,
+      //                   icon: "",
+      //                   isDelete: 0,
+      //                   isShow: true,
+      //                   navigationId: item.sid ? item.sid : item.id,
+      //                   scale: 1,
+      //                   type: "sky",
+      //                   workId: state.baseInfo.workId,
+      //                 },
+      //               },
+      //               navigationId: item.sid ? item.sid : item.id,
+      //             });
+      //             break;
+      //           case "workVisualAngleList":
+      //             state.baseInfo[key].push({
+      //               hlookat: 0,
+      //               icon: item.icon,
+      //               // id: 0,
+      //               vlookat: 0,
+      //               vlookatmax: 90,
+      //               vlookatmin: -90,
+      //               workId: state.baseInfo.workId,
+      //               navigationId: item.sid ? item.sid : item.id,
+      //             });
+      //             break;
+      //           case "workExplanationList":
+      //             console.error("workExplanationList");
+      //             state.baseInfo[key].push({
+      //               fodderId: null,
+      //               audioName: "",
+      //               audioUrl: "",
+      //               openByDefault: true,
+      //               navigationId: item.sid ? item.sid : item.id,
+      //               playRepeat: true,
+      //             });
+      //             break;
+      //         }
+      //       }
 
-            // if (key == "workCustomMaskList") {
-            //   let hasMask = false;
-            //   state.baseInfo[key].forEach((mask_item, mask_index) => {
-            //     if (mask_item.navigationId == item.id) {
-            //       hasMask = true;
-            //     }
-            //   });
-            //   if (!hasMask) {
-            //     state.baseInfo[key].push({
-            //       data: {
-            //         earth: {
-            //           antidistorted: true,
-            //           fodderId: null,
-            //           icon: "",
-            //           isDelete: 0,
-            //           isShow: false,
-            //           navigationId: item.id,
-            //           scale: 1,
-            //           type: "earth",
-            //           workId: state.baseInfo.workId,
-            //         },
-            //         sky: {
-            //           antidistorted: true,
-            //           fodderId: null,
-            //           icon: "",
-            //           id: 7,
-            //           isDelete: 0,
-            //           isShow: true,
-            //           navigationId: item.id,
-            //           scale: 1,
-            //           type: "sky",
-            //           workId: state.baseInfo.workId,
-            //         },
-            //       },
-            //       navigationId: item.id,
-            //     });
-            //   }
-            // }
-            // if (key == "workVisualAngleList") {
-            //   let hasVisual = false;
-            //   state.baseInfo[key].forEach((visual_item, visual_index) => {
-            //     if (visual_item.navigationId == item.id) {
-            //       hasVisual = true;
-            //       visual_item.icon = item.icon;
-            //     }
-            //   });
-            //   if (!hasVisual) {
-            //     state.baseInfo[key].push({
-            //       hlookat: 0,
-            //       icon: item.icon,
-            //       // id: 0,
-            //       vlookat: 0,
-            //       vlookatmax: 90,
-            //       vlookatmin: -90,
-            //       workId: state.baseInfo.workId,
-            //       navigationId: item.id,
-            //     });
-            //   }
-            // }
-            // if(key=='workExplanationList'){
+      //       // if (key == "workCustomMaskList") {
+      //       //   let hasMask = false;
+      //       //   state.baseInfo[key].forEach((mask_item, mask_index) => {
+      //       //     if (mask_item.navigationId == item.id) {
+      //       //       hasMask = true;
+      //       //     }
+      //       //   });
+      //       //   if (!hasMask) {
+      //       //     state.baseInfo[key].push({
+      //       //       data: {
+      //       //         earth: {
+      //       //           antidistorted: true,
+      //       //           fodderId: null,
+      //       //           icon: "",
+      //       //           isDelete: 0,
+      //       //           isShow: false,
+      //       //           navigationId: item.id,
+      //       //           scale: 1,
+      //       //           type: "earth",
+      //       //           workId: state.baseInfo.workId,
+      //       //         },
+      //       //         sky: {
+      //       //           antidistorted: true,
+      //       //           fodderId: null,
+      //       //           icon: "",
+      //       //           id: 7,
+      //       //           isDelete: 0,
+      //       //           isShow: true,
+      //       //           navigationId: item.id,
+      //       //           scale: 1,
+      //       //           type: "sky",
+      //       //           workId: state.baseInfo.workId,
+      //       //         },
+      //       //       },
+      //       //       navigationId: item.id,
+      //       //     });
+      //       //   }
+      //       // }
+      //       // if (key == "workVisualAngleList") {
+      //       //   let hasVisual = false;
+      //       //   state.baseInfo[key].forEach((visual_item, visual_index) => {
+      //       //     if (visual_item.navigationId == item.id) {
+      //       //       hasVisual = true;
+      //       //       visual_item.icon = item.icon;
+      //       //     }
+      //       //   });
+      //       //   if (!hasVisual) {
+      //       //     state.baseInfo[key].push({
+      //       //       hlookat: 0,
+      //       //       icon: item.icon,
+      //       //       // id: 0,
+      //       //       vlookat: 0,
+      //       //       vlookatmax: 90,
+      //       //       vlookatmin: -90,
+      //       //       workId: state.baseInfo.workId,
+      //       //       navigationId: item.id,
+      //       //     });
+      //       //   }
+      //       // }
+      //       // if(key=='workExplanationList'){
 
-            // }
-          });
-        });
-      }
-      console.error(state.baseInfo["workExplanationList"]);
+      //       // }
+      //     });
+      //   });
+      // }
+      // console.error(state.baseInfo["workVisualAngleList"]);
     },
     initbaseInfo(state, payload) {
       let data = {
@@ -288,6 +309,9 @@ export default {
     updateBaseInfo(state, payload) {
       for (let key in payload) {
         state.baseInfo[key] = payload[key];
+        // if (key == "navigationTrees") {
+        //   console.error(state.sceneList);
+        // }
       }
     },
   },

+ 55 - 12
packages/qjkankan-editor/src/Store/modules/explanation.js

@@ -7,30 +7,73 @@ let vue = new Vue();
 export default {
   namespaced: true,
   state() {
-    return {};
+    return {
+      workExplanationList: [],
+    };
+  },
+  getters: {
+    workExplanationList: (state) => state.workExplanationList,
   },
-  getters: {},
   mutations: {
+    setExplanationList(state, payload) {
+      let { sceneList, workExplanationList } = payload;
+      state.workExplanationList = workExplanationList;
+      console.error("setExplanationList", sceneList, state.workExplanationList);
+
+      sceneList.forEach((s_item, s_index) => {
+        if (!state.workExplanationList.some((w_item) => s_item.id == w_item.navigationId || s_item.sid == w_item.navigationId)) {
+          console.error(s_index, "不存在");
+
+          state.workExplanationList.push({
+            fodderId: null,
+            audioName: "",
+            audioUrl: "",
+            openByDefault: true,
+            navigationId: s_item.sid ? s_item.sid : s_item.id,
+            playRepeat: true,
+          });
+        } else {
+          // console.error(s_index, "存在");
+          let idx = state.workExplanationList.findIndex((idx_item) => s_item.id == idx_item.navigationId || s_item.sid == idx_item.navigationId);
+          // console.error("idx", idx, s_item.sid, s_item.id);
+          if (idx >= 0 && s_item.sid && typeof s_item.id == "number") {
+            // console.error(s_index, idx, "接口保存后的数据");
+            state.workExplanationList[idx].navigationId = s_item.id;
+          }
+        }
+      });
+
+      state.workExplanationList.forEach((item, index) => {
+        if (!sceneList.some((j_item) => item.navigationId == j_item.id || item.navigationId == j_item.sid)) {
+          // console.error(index, "删除了");
+          state.workExplanationList.splice(index, 1);
+        }
+      });
+
+      console.error(state.workExplanationList);
+    },
     setData(state, payload) {},
   },
   actions: {
     save({ commit, state, rootState }) {
-      console.error(rootState.base.baseInfo.workExplanationList);
-      let list = [];
-      if (rootState.base.sceneList.length != rootState.base.baseInfo.workExplanationList.length) {
-        list = rootState.base.baseInfo.workExplanationList.filter((item1) => rootState.base.sceneList.some((item2) => item2.id === item1.navigationId));
-      } else {
-        list = rootState.base.baseInfo.workExplanationList;
-      }
-      console.error(list);
-
+      // console.error(rootState.base.baseInfo.workExplanationList);
+      // let list = [];
+      // if (rootState.base.sceneList.length != rootState.base.baseInfo.workExplanationList.length) {
+      //   list = rootState.base.baseInfo.workExplanationList.filter((item1) => rootState.base.sceneList.some((item2) => item2.id === item1.navigationId));
+      // } else {
+      //   list = rootState.base.baseInfo.workExplanationList;
+      // }
+      console.error(state.workExplanationList);
+      // $waiting.hide();
+      // return;
       explanationSave(
         {
-          list,
+          list: state.workExplanationList,
         },
         () => {
           vue.$msg.success(i18n.t("gather.save_done"));
           $waiting.hide();
+          this.commit("base/updateBaseInfo", { workExplanationList: state.workExplanationList });
         },
         () => {}
       );

+ 250 - 11
packages/qjkankan-editor/src/Store/modules/hotspot.js

@@ -2,31 +2,270 @@ import Vue from "vue";
 import { i18n } from "@/lang";
 import { workHotSave } from "@/api";
 import { $waiting } from "@/components/shared/loading";
+
+import browser from "@/utils/browser";
+import { deepClone, isSameObject } from "@/utils/other.js";
 let vue = new Vue();
 export default {
   namespaced: true,
   state() {
-    return {};
+    return {
+      hotspotList: [],
+      currentHotsopts: [],
+      hotspot: null,
+      hotspotTypeList: {
+        scene: "scene",
+        image: "image",
+        video: "video",
+        audio: "audio",
+        link: "hyperlink",
+        textarea: "textarea",
+        tag: null,
+        imageText: "imageTextInfo",
+        article: "articleInfo",
+        pdf: "pdfInfo",
+        phone: "phoneInfo",
+      },
+      hotspotIconTypeList: {
+        system_icon: null,
+        custom_image: "customIconInfo",
+        serial_frame: "serialFrameInfo",
+        personalized_tag: "personalizedTagInfo",
+      },
+      dataType: {
+        customIconInfo: {
+          // 热点图标类型为自定义图标时,图标的数据
+          img: "",
+        },
+        serialFrameInfo: {
+          // 热点图标类型为序列帧时,序列帧的数据
+          img: "",
+          frameNumber: 0, // 总帧数
+          duration: 0, // 总播放时长(秒)
+        },
+        personalizedTagInfo: {
+          // 热点图标类型为个性标签时,个性标签的数据
+          isShowLine: true,
+          lineDirection: "left-top",
+          fillColor: "rgba(0, 0, 0, 0.5)",
+          borderColor: "rgba(255, 255, 255, 0.8)",
+          textColor: "rgba(255, 255, 255, 1)",
+          textDirection: "left-right",
+          isTextWrap: false,
+          textNumPerLine: 10,
+        },
+
+        scene: null,
+        hyperlink: "",
+        textarea: "",
+        image: [],
+        audio: "",
+        video: "",
+        imageTextInfo: {
+          // 热点类型为图文时,图文内容
+          imageList: [],
+          text: "",
+          isApplyToAll: true,
+          audio: {},
+        },
+        phoneInfo: {
+          // 热点类型为电话时,对应数据
+          phone: "",
+        },
+        pdfInfo: {
+          // 热点类型为pdf时,对应数据
+          name: "",
+          url: "",
+        },
+        articleInfo: {
+          html: "",
+        },
+      },
+    };
   },
   getters: {
-    currentScene: (state) => state.currentScene,
+    hotspot: (state) => state.hotspot,
+    currentHotsopts: (state, getters, rootState, rootGetters) => {
+      state.currentHotsopts = state.hotspotList.filter((item) => item.navigationId == rootState.scene.currentScene.id || item.navigationId == rootState.scene.currentScene.sid);
+      return state.currentHotsopts;
+    },
+    hotspotList: (state, getters, rootState, rootGetters) => {
+      let hotspots = rootState.base.baseInfo.workHotList;
+      if (hotspots.length && !state.hotspotList.length) {
+        state.hotspotList = hotspots;
+        console.error(state.hotspotList);
+      }
+      if (state.hotspotList.length) {
+        state.hotspotList.forEach((item, index) => {
+          if (item.content) {
+            let hotSpotType = item.hotspotType;
+            for (let key in state.hotspotTypeList) {
+              let value = state.hotspotTypeList[key];
+              if (key == hotSpotType && item.content[value]) {
+                item[value] = item.content[value];
+              } else if (value) {
+                item[value] = state.dataType[value];
+              }
+            }
+
+            let hotSpotIconType = item.hotspotIconType;
+            for (let key in state.hotspotIconTypeList) {
+              let value = state.hotspotIconTypeList[key];
+              if (key == hotSpotIconType && item.content[value]) {
+                item[value] = item.content[value];
+              } else if (value) {
+                item[value] = state.dataType[value];
+              }
+            }
+          }
+        });
+      }
+
+      return state.hotspotList;
+    },
+    // 1.3.0 新增层级后所有热点类型不同汇总显示的ICON
+    hotspotIcon: (state) => {
+      const category = state.hotspot && state.hotspot.hotspotIconType ? state.hotspot.hotspotIconType : "";
+      switch (category) {
+        case "system_icon":
+          return {
+            img: state.hotspot.img,
+            type: "system_icon",
+          };
+        case "custom_image":
+          return {
+            ...state.hotspot.customIconInfo,
+            type: "custom_image",
+          };
+        case "serial_frame":
+          return {
+            ...state.hotspot.serialFrameInfo,
+            img: state.hotspot.serialFrameInfo.img,
+            type: "serial_frame",
+          };
+        case "personalized_tag":
+          return {
+            ...state.hotspot.personalizedTagInfo,
+            img: "",
+            type: "personalized_tag",
+          };
+        default:
+          return {
+            img: "",
+          };
+      }
+    },
+    // currentScene: (state) => state.currentScene,
   },
   mutations: {
-    setData(state, payload) {
-      this.commit("base/initbaseInfo");
-      // state.baseInfo = payload;
-      for (let key in state.baseInfo) {
-        if (payload[key]) {
-          state.baseInfo[key] = payload[key];
-        }
+    SetHotspot(state, data) {
+      console.error(data);
+      state.hotspot = data;
+      this.commit("BackupHotSpot", browser.CloneObject(data));
+    },
+    updateHotspot(state, payload) {
+      console.error(payload.id);
+      if (payload.id) {
+        // 编辑
+        state.hotspotList.forEach((item, index) => {
+          if (item.id == payload.id) {
+            state.hotspotList[index] = payload;
+          }
+        });
+        state.currentHotsopts.forEach((item, index) => {
+          if (item.id == payload.id) {
+            state.currentHotsopts[index] = payload;
+          }
+        });
+      } else {
+        //新增
+        payload.id = "add_" + new Date().getTime();
+        state.hotspotList.push(payload);
       }
+
+      console.error(state.hotspotList);
+    },
+    processData(state, payload) {
+      // state.hotspot.content = {};
+      let list = state.hotspotList;
+      list.forEach((item) => {
+        console.error(item);
+        if (!item.content) {
+          item.content = {};
+        }
+        let hotSpotType = item.hotspotType;
+
+        for (let key in state.hotspotTypeList) {
+          let value = state.hotspotTypeList[key];
+          if (key == hotSpotType) {
+            if (value) {
+              item.content[value] = item[value];
+            }
+          }
+          delete item[value];
+        }
+
+        let hotSpotIconType = item.hotspotIconType;
+        for (let key in state.hotspotIconTypeList) {
+          let value = state.hotspotIconTypeList[key];
+          if (key == hotSpotIconType) {
+            if (value) {
+              item.content[value] = item[value];
+            }
+          }
+          delete item[value];
+        }
+      });
+      console.error(state.hotspotList, list);
     },
   },
   actions: {
     save({ commit, state, rootState }, payload) {
+      let list = deepClone(state.hotspotList);
+
+      list.forEach((item) => {
+        let current = rootState.base.sceneList.find((s_item) => s_item.sid && s_item.sid == item.navigationId);
+        if (current) {
+          item.navigationId = current.id;
+        }
+        if (typeof item.id != "number" && item.id.indexOf("add") != -1) {
+          delete item.id;
+        }
+        if (!item.content) {
+          item.content = {};
+        }
+        let hotSpotType = item.hotspotType;
+
+        for (let key in state.hotspotTypeList) {
+          let value = state.hotspotTypeList[key];
+          if (key == hotSpotType) {
+            if (value) {
+              item.content[value] = item[value];
+            }
+          }
+          delete item[value];
+        }
+
+        let hotSpotIconType = item.hotspotIconType;
+        for (let key in state.hotspotIconTypeList) {
+          let value = state.hotspotIconTypeList[key];
+          if (key == hotSpotIconType) {
+            if (value) {
+              item.content[value] = item[value];
+            }
+          }
+          delete item[value];
+        }
+      });
+      console.error(state.hotspotList, list);
+
+      let data = { list, workId: rootState.base.baseInfo.workId };
       workHotSave(
-        payload,
-        () => {},
+        data,
+        () => {
+          vue.$msg.success(i18n.t("gather.save_done"));
+          $waiting.hide();
+        },
         () => {}
       );
     },

+ 81 - 14
packages/qjkankan-editor/src/Store/modules/mask.js

@@ -7,41 +7,108 @@ let vue = new Vue();
 export default {
   namespaced: true,
   state() {
-    return {};
+    return {
+      workCustomMaskList: [],
+    };
+  },
+  getters: {
+    workCustomMaskList: (state, getters, rootState, rootGetters) => {
+      return state.workCustomMaskList;
+    },
   },
-  getters: {},
   mutations: {
+    setCustomMaskList(state, payload) {
+      let { sceneList, workCustomMaskList, workId } = payload;
+      state.workCustomMaskList = workCustomMaskList;
+      console.error("setCustomMaskList", sceneList, state.workCustomMaskList);
+
+      sceneList.forEach((s_item, s_index) => {
+        if (!state.workCustomMaskList.some((w_item) => s_item.id == w_item.navigationId || s_item.sid == w_item.navigationId)) {
+          // console.error(s_index, "不存在");
+          state.workCustomMaskList.push({
+            data: {
+              earth: {
+                antidistorted: true,
+                fodderId: null,
+                icon: "",
+                isDelete: 0,
+                isShow: false,
+                navigationId: s_item.sid ? s_item.sid : s_item.id,
+                scale: 1,
+                type: "earth",
+                workId,
+              },
+              sky: {
+                antidistorted: true,
+                fodderId: null,
+                icon: "",
+                isDelete: 0,
+                isShow: true,
+                navigationId: s_item.sid ? s_item.sid : s_item.id,
+                scale: 1,
+                type: "sky",
+                workId,
+              },
+            },
+            navigationId: s_item.sid ? s_item.sid : s_item.id,
+          });
+        } else {
+          // console.error(s_index, "存在");
+          let idx = state.workCustomMaskList.findIndex((idx_item) => s_item.id == idx_item.navigationId || s_item.sid == idx_item.navigationId);
+          // console.error("idx", idx, s_item.sid, s_item.id);
+          if (idx >= 0 && s_item.sid && typeof s_item.id == "number") {
+            // console.error(s_index, idx, "接口保存后的数据");
+            state.workCustomMaskList[idx].navigationId = s_item.id;
+            state.workCustomMaskList[idx].data.sky.navigationId = s_item.id;
+            state.workCustomMaskList[idx].data.earth.navigationId = s_item.id;
+          }
+        }
+      });
+
+      state.workCustomMaskList.forEach((item, index) => {
+        if (!sceneList.some((j_item) => item.navigationId == j_item.id || item.navigationId == j_item.sid)) {
+          // console.error(index, "删除了");
+          state.workCustomMaskList.splice(index, 1);
+        }
+      });
+
+      console.error(state.workCustomMaskList);
+    },
     setData(state, payload) {},
   },
   actions: {
     save({ commit, state, rootState }) {
-      console.error(rootState.base.baseInfo.workCustomMaskList);
-      let workCustomMaskList = [];
-      if (rootState.base.sceneList.length != rootState.base.baseInfo.workCustomMaskList.length) {
-        workCustomMaskList = rootState.base.baseInfo.workCustomMaskList.filter((item1) => rootState.base.sceneList.some((item2) => item2.id === item1.navigationId));
-      } else {
-        workCustomMaskList = rootState.base.baseInfo.workCustomMaskList;
-      }
-      console.error(workCustomMaskList);
+      // console.error(rootState.base.baseInfo.workCustomMaskList);
+      // let workCustomMaskList = [];
+      // if (rootState.base.sceneList.length != rootState.base.baseInfo.workCustomMaskList.length) {
+      //   workCustomMaskList = rootState.base.baseInfo.workCustomMaskList.filter((item1) => rootState.base.sceneList.some((item2) => item2.id === item1.navigationId));
+      // } else {
+      //   workCustomMaskList = rootState.base.baseInfo.workCustomMaskList;
+      // }
+      // console.error(workCustomMaskList);
 
       let list = [];
 
-      workCustomMaskList.forEach((item) => {
+      state.workCustomMaskList.forEach((item) => {
         //组装服务端需要的数据
         for (let key in item.data) {
-          console.error(key)
+          console.error(key);
           list.push(item.data[key]);
         }
       });
-      console.error(list)
+      console.error(list);
+      // $waiting.hide();
+      // return;
       // return
       maskSave(
         {
           list,
         },
-        () => {
+        (res) => {
           vue.$msg.success(i18n.t("gather.save_done"));
           $waiting.hide();
+          console.error(res);
+          this.commit("base/updateBaseInfo", { workCustomMaskList: state.workCustomMaskList });
         },
         () => {}
       );

+ 55 - 31
packages/qjkankan-editor/src/Store/modules/navigation.js

@@ -7,6 +7,7 @@ export default {
   namespaced: true,
   state() {
     return {
+      isSave: false,
       catalogTopology: [],
       currentSecondId: null,
       currentRootId: null,
@@ -21,7 +22,11 @@ export default {
       navigationTrees: [],
     };
   },
-  getters: { currentRootId: (state) => state.currentRootId, currentSecondId: (state) => state.currentSecondId },
+  getters: {
+    isSave: (state) => state.isSave,
+    currentRootId: (state) => state.currentRootId,
+    currentSecondId: (state) => state.currentSecondId,
+  },
   mutations: {
     setData(state, payload) {
       for (let key in payload) {
@@ -32,8 +37,9 @@ export default {
   },
   actions: {
     save({ commit, state, rootState }) {
-      console.error(rootState.base.baseInfo.navigationTrees);
-      rootState.base.baseInfo.navigationTrees.forEach((item, index) => {
+      let list = JSON.parse(JSON.stringify(rootState.base.baseInfo.navigationTrees));
+      // console.error(rootState.base.baseInfo.navigationTrees);
+      list.forEach((item, index) => {
         item.sort = index;
         if (typeof item.id != "number" && item.id.indexOf("add_") != -1) {
           delete item.id;
@@ -54,39 +60,57 @@ export default {
           });
         });
       });
-      console.error(rootState.base.baseInfo.navigationTrees);
+      console.error(rootState.base.baseInfo.navigationTrees, list);
       // $waiting.hide();
       // return;
-      navigationSave(
-        { list: rootState.base.baseInfo.navigationTrees },
-        (res) => {
-          $waiting.hide();
-          if (res.code == 0) {
-            vue.$msg.success(i18n.t("gather.save_done"));
-            this.commit("TakeInfoSnapShotAtSave");
-            this.commit("base/updateBaseInfo", { navigationTrees: res.data });
-            setTimeout(() => {
-              if (state.saveFristScene) {
-                let data = {};
-                if (rootState.base.baseInfo.firstScene) {
-                  let firstScene = rootState.base.sceneList.find((item) => item.sceneCode == rootState.base.baseInfo.firstScene.sceneCode);
-                  if (firstScene) {
-                    data = { navigationId: rootState.base.baseInfo.firstScene.id, operType: "add" };
+
+      return new Promise((resolve, reject) => {
+        navigationSave(
+          { list },
+          (res) => {
+            $waiting.hide();
+            if (res.code == 0) {
+              vue.$msg.success(i18n.t("gather.save_done"));
+              // this.commit("TakeInfoSnapShotAtSave");
+              this.commit("base/updateBaseInfo", { navigationTrees: res.data });
+              if (rootState.scene.currentScene) {
+                setTimeout(() => {
+                  // console.error("有当前场景", rootState.scene.currentScene);
+                  let curreentScene = rootState.base.sceneList.find((item) => item.sid && item.sid == rootState.scene.currentScene.sid);
+                  if (curreentScene) {
+                    this.commit("scene/setCurrentScene", curreentScene);
                   }
-                } else {
-                  data = { navigationId: null, operType: "delete" };
-                }
-                initialSet(data, (res) => {
-                  commit("setData", { saveFristScene: false });
-                });
+                }, 0);
               }
-            }, 0);
+              this.commit("base/ininDefaultData");
+              state.isSave = true;
+
+              setTimeout(() => {
+                resolve();
+                if (state.saveFristScene) {
+                  let data = {};
+                  // console.error("有当前场景",rootState.base.baseInfo.firstScene);
+                  if (rootState.base.baseInfo.firstScene) {
+                    let firstScene = rootState.base.sceneList.find((item) => item.sceneCode == rootState.base.baseInfo.firstScene.sceneCode);
+                    if (firstScene) {
+                      data = { navigationId: firstScene.id, operType: "add" };
+                    }
+                  } else {
+                    data = { navigationId: null, operType: "delete" };
+                  }
+                  initialSet(data, (res) => {
+                    commit("setData", { saveFristScene: false });
+                  });
+                }
+              }, 0);
+            }
+          },
+          (err) => {
+            $waiting.hide();
+            reject();
           }
-        },
-        (err) => {
-          $waiting.hide();
-        }
-      );
+        );
+      });
     },
   },
 };

+ 10 - 1
packages/qjkankan-editor/src/Store/modules/scene.js

@@ -52,6 +52,7 @@ export default {
   },
   getters: {
     list: (state) => state.list,
+    saveApiList: (state) => state.saveApiList,
     secondaryList: (state) => state.secondaryList,
     currentCatalogRoot: (state) => state.currentCatalogRoot,
     currentScenesList: (state) => state.currentScenesList,
@@ -87,11 +88,19 @@ export default {
       if (!state.saveApiList.some((i) => i == payload)) {
         state.saveApiList.push(payload);
       }
-      console.error("saveApiList", state.saveApiList);
+      console.error("setSaveApiList", state.saveApiList);
+    },
+    removeSaveApi(state, payload) {
+      if (state.saveApiList.some((i) => i == payload)) {
+        let idx = state.saveApiList.findIndex((item) => item == payload);
+        state.saveApiList.splice(idx, 1);
+      }
+      console.error("removeSaveApi", state.saveApiList);
     },
 
     // 设置当前场景
     setCurrentScene(state, payload) {
+      console.error('setCurrentScene')
       state.currentScene = payload;
     },
     // 设置当前二级分组

+ 86 - 14
packages/qjkankan-editor/src/Store/modules/screen.js

@@ -7,10 +7,78 @@ let vue = new Vue();
 export default {
   namespaced: true,
   state() {
-    return {};
+    return {
+      workVisualAngleList: [],
+    };
+  },
+  getters: {
+    workVisualAngleList: (state, getters, rootState, rootGetters) => {
+      // let list = rootState.base.baseInfo.workVisualAngleList;
+      // let sceneList = rootState.base.sceneList;
+      // console.error("******", list, sceneList);
+      // if (!state.workVisualAngleList.length) {
+      //   state.workVisualAngleList = list;
+      // }
+      return state.workVisualAngleList;
+    },
   },
-  getters: {},
   mutations: {
+    setVisualAngleList(state, payload) {
+      let { sceneList, workVisualAngleList } = payload;
+      state.workVisualAngleList = workVisualAngleList;
+      console.error("setVisualAngleList", sceneList, state.workVisualAngleList);
+
+      sceneList.forEach((s_item, s_index) => {
+        if (!state.workVisualAngleList.some((w_item) => s_item.id == w_item.navigationId || s_item.sid == w_item.navigationId)) {
+          // console.error(s_index, "不存在");
+          state.workVisualAngleList.push({
+            hlookat: 0,
+            icon: s_item.icon,
+            vlookat: 0,
+            vlookatmax: 90,
+            vlookatmin: -90,
+            navigationId: s_item.sid ? s_item.sid : s_item.id,
+          });
+        } else {
+          // console.error(s_index, "存在");
+          let idx = state.workVisualAngleList.findIndex((idx_item) => s_item.id == idx_item.navigationId || s_item.sid == idx_item.navigationId);
+          // console.error("idx", idx, s_item.sid, s_item.id);
+          if (idx >= 0 && s_item.sid && typeof s_item.id == "number") {
+            // console.error(s_index, idx, "接口保存后的数据");
+            state.workVisualAngleList[idx].navigationId = s_item.id;
+          }
+        }
+
+        // if (!workVisualAngleList.some((w_item) => s_item.id == w_item.navigationId || s_item.sid == w_item.navigationId)) {
+        //   console.error("1111");
+        //   state.workVisualAngleList.push({
+        //     hlookat: 0,
+        //     icon: s_item.icon,
+        //     vlookat: 0,
+        //     vlookatmax: 90,
+        //     vlookatmin: -90,
+        //     navigationId: s_item.sid ? s_item.sid : s_item.id,
+        //   });
+        // } else {
+        //   let idx = state.workVisualAngleList.findIndex((idx_item) => s_item.id == idx_item.navigationId || s_item.sid == idx_item.navigationId);
+        //   console.error("2222", idx);
+        //   if (idx && s_item.sid && typeof s_item.id == "number") {
+        //     //接口保存后的数据
+        //     console.error("接口保存后的数据");
+        //     state.workVisualAngleList[idx].navigationId = s_item.id;
+        //   }
+        // }
+      });
+
+      state.workVisualAngleList.forEach((item, index) => {
+        if (!sceneList.some((j_item) => item.navigationId == j_item.id || item.navigationId == j_item.sid)) {
+          // console.error(index, "删除了");
+          state.workVisualAngleList.splice(index, 1);
+        }
+      });
+
+      console.error(state.workVisualAngleList);
+    },
     setData(state, payload) {
       this.commit("base/initbaseInfo");
       // state.baseInfo = payload;
@@ -23,29 +91,33 @@ export default {
   },
   actions: {
     applyInitVisualToAll({ commit, state, rootState }, payload) {
-      rootState.base.baseInfo.workVisualAngleList.forEach((item, index) => {
+      state.workVisualAngleList.forEach((item, index) => {
         item.vlookatmin = payload[0];
         item.vlookatmax = payload[1];
       });
-      console.error(rootState.base.baseInfo.workVisualAngleList);
+      console.error(state.workVisualAngleList);
     },
     save({ commit, state, rootState }) {
-      console.error(rootState.base.baseInfo.workVisualAngleList);
-      let workVisualAngleList = [];
-      if (rootState.base.sceneList.length != rootState.base.baseInfo.workVisualAngleList.length) {
-        workVisualAngleList = rootState.base.baseInfo.workVisualAngleList.filter((item1) => rootState.base.sceneList.some((item2) => item2.id === item1.navigationId));
-      } else {
-        workVisualAngleList = rootState.base.baseInfo.workVisualAngleList;
-      }
-      console.error(workVisualAngleList);
+      // console.error(rootState.base.baseInfo.workVisualAngleList);
+      // console.error(rootState.base.sceneList);
+      // let workVisualAngleList = [];
+      // if (rootState.base.sceneList.length != rootState.base.baseInfo.workVisualAngleList.length) {
+      //   workVisualAngleList = rootState.base.baseInfo.workVisualAngleList.filter((item1) => rootState.base.sceneList.some((item2) => item2.id === item1.navigationId));
+      // } else {
+      //   workVisualAngleList = rootState.base.baseInfo.workVisualAngleList;
+      // }
+      console.error("save", state.workVisualAngleList);
+      $waiting.hide();
+      // return
       visualSave(
         {
-          list: workVisualAngleList,
+          list: state.workVisualAngleList,
         },
 
-        () => {
+        (res) => {
           vue.$msg.success(i18n.t("gather.save_done"));
           $waiting.hide();
+          this.commit("base/updateBaseInfo", { workVisualAngleList: res.data });
         },
         () => {}
       );

+ 1 - 1
packages/qjkankan-editor/src/Store/modules/tags.js

@@ -2,7 +2,7 @@ export default {
   namespaced: true,
   state() {
     return {
-      currentEditTag: '',
+      currentEditTag: "",
       // 是否在确认热点位置状态
       isConfirmingPosi: false,
     };

+ 30 - 7
packages/qjkankan-editor/src/components/dragTree/index.vue

@@ -129,7 +129,7 @@ import SceneInGroup from "@/components/sceneInGroupInEditor.vue";
 import MaterialSelector from "@/components/materialSelector.vue";
 
 import { isUpgradeAdapter } from "@/utils/fixVersion";
-import { ossImagePreviewUrlSuffix } from "@/utils/other.js";
+import { ossImagePreviewUrlSuffix, getRandomSid } from "@/utils/other.js";
 export default {
   components: {
     // VueTreeList,
@@ -175,18 +175,31 @@ export default {
       handler: function (newVal, oldVal) {
         if (newVal) {
           if (this.info.firstScene) {
-            if (!newVal.some((item) => item.id == this.info.firstScene.id)) {
+            if (!newVal.some((item) => item.id == this.info.firstScene.id) && (this.currentScene.id == this.info.firstScene.id )) {
               this.$store.commit("base/setData", { firstScene: null });
             }
-
-            if (!newVal.some((item) => item.id == this.currentScene.id)) {
-              this.$store.commit("scene/setCurrentScene", null);
-            }
+     
+            // console.error("设置空");
+            // if (!newVal.some((item) => item.id == this.currentScene.id || item.id == this.currentScene.sid)) {
+            //   console.error("设置空");
+            //   this.$store.commit("scene/setCurrentScene", null);
+            // }
           }
         }
       },
       deep: true,
     },
+
+    "info.firstScene": {
+      // immediate: true,
+      handler: function (newVal, oldVal) {
+        if (!newVal) {
+          console.error("设置空");
+          // this.$store.commit("scene/setCurrentScene", null);
+        }
+      },
+      deep: true,
+    },
   },
   data() {
     return {
@@ -313,12 +326,15 @@ export default {
     handlerGroup(data, note, e) {
       if (data.type == "group") {
         // if (data.children.length) {
-        this.$refs.sceneTree.store.nodesMap[data.id].expanded = !this.$refs.sceneTree.store.nodesMap[data.id].expanded;
+
+        this.$refs.sceneTree.store.nodesMap[data.id].expanded = this.insertTag ? true : !this.$refs.sceneTree.store.nodesMap[data.id].expanded;
         if (this.$refs.sceneTree.store.nodesMap[data.id].expanded) {
           this.handleNodeExpand(data);
         } else {
           this.handleNodeCollapse(data);
         }
+
+        this.insertTag = null;
         // }
       }
     },
@@ -346,6 +362,7 @@ export default {
             parentId: null,
             level: this.insertTag.level + 1,
             id: "add_" + roundId,
+            sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
             // id: "s_" + this.$randomWord(true, 8, 8),
           });
         } else if (item.materialType === "3D") {
@@ -361,6 +378,7 @@ export default {
             level: this.insertTag.level + 1,
             version: isUpgradeAdapter(item.isUpgrade), // 'V3' OR 'V4'. 全景看看v1.3新增
             id: "add_" + roundId,
+            sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
 
             // id: "s_" + this.$randomWord(true, 8, 8),
             // fodderId: item.id,
@@ -509,11 +527,13 @@ export default {
       let roundId = new Date().getTime();
       let group = {
         id: "add_" + roundId,
+        sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
         name: data ? this.$i18n.t("navigation.group_two") : this.$i18n.t("navigation.group_one"),
         type: "group",
         level: data ? 1 : 0,
         children: [],
       };
+      console.error(group);
       if (data) {
         // if (data.children.length && data.children[0].type != "group") {
         //   //新增子目录的时候,如果目录里面没有子目录,新增一个默认目录包含旧数据
@@ -556,6 +576,7 @@ export default {
               let list = [];
               let defaultDir = {
                 id: "add_" + (this.getRoundId() + 1),
+                sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
                 sort: 0,
                 name: this.$i18n.t("navigation.default_group_two"),
                 type: "group",
@@ -571,6 +592,7 @@ export default {
               let list = [];
               let defaultDir = {
                 id: "add_" + (this.getRoundId() + 1),
+                sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
                 sort: 0,
                 name: this.$i18n.t("navigation.default_group_two"),
                 type: "group",
@@ -601,6 +623,7 @@ export default {
               let list = [];
               let defaultDir = {
                 id: "add_" + (this.getRoundId() + 1),
+                sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
                 sort: 0,
                 name: this.$i18n.t("navigation.default_group_two"),
                 type: "group",

+ 10 - 13
packages/qjkankan-editor/src/core/hotspot.js

@@ -44,14 +44,17 @@ const convertBaseStyle = (dest, origin) => {
 
     if ("visible" in origin && typeof origin.visible == "boolean") {
       dest.visible = origin.visible ? 0 : 1;
-      origin.titleDisplayMode = origin.visible ? "always" : "never";
+      // origin.titleDisplayMode = origin.visible ? "always" : "never";
+      origin.titleDisplayMode = origin.visible ? 1 : 0;
       delete origin.visible;
       dest.style.position = "top";
     }
-    if (origin && origin.titleDisplayMode == "always") {
+    // if (origin && origin.titleDisplayMode == "always") {
+    if (origin && origin.titleDisplayMode == 1) {
       dest.visible = 0;
     }
-    if (origin && origin.titleDisplayMode == "never") {
+    // if (origin && origin.titleDisplayMode == "never") {
+    if (origin && origin.titleDisplayMode == 0) {
       dest.visible = 1;
     }
     if (origin && origin.titleDisplayMode == "hover") {
@@ -96,9 +99,7 @@ const coverSystemIconPart = (origin) => {
 };
 
 const coverImageconPart = (origin) => {
-  const defaultImage = config.getStaticResource(
-    "/panoassets/images/hotspot/image_place_holder.png"
-  );
+  const defaultImage = config.getStaticResource("/panoassets/images/hotspot/image_place_holder.png");
   const duplicate = structuredClone(initState);
   duplicate.id = origin.name;
   duplicate.title = origin.hotspotTitle;
@@ -113,9 +114,7 @@ const coverImageconPart = (origin) => {
 };
 const coverSerialFrame = (origin) => {
   const duplicate = structuredClone(initState);
-  const defaultImage = config.getStaticResource(
-    "/panoassets/images/hotspot/image_place_holder.png"
-  );
+  const defaultImage = config.getStaticResource("/panoassets/images/hotspot/image_place_holder.png");
   // console.log('defaultImage', defaultImage);
   duplicate.id = origin.name;
   duplicate.title = origin.hotspotTitle;
@@ -123,10 +122,7 @@ const coverSerialFrame = (origin) => {
   duplicate.atv = origin.atv;
   duplicate.type = 2;
 
-  duplicate.icon =
-    origin.serialFrameInfo.img +
-      "?x-oss-process=image/resize,w_128,q_80" ||
-    defaultImage;
+  duplicate.icon = origin.serialFrameInfo.img + "?x-oss-process=image/resize,w_128,q_80" || defaultImage;
   duplicate.link = origin.link || "";
   duplicate.size = origin.size;
   convertBaseStyle(duplicate, origin);
@@ -148,6 +144,7 @@ const coverpersonalizedTag = (origin) => {
 
 export const convertJQHotspot = (origin) => {
   const type = origin.hotspotIconType;
+  
   switch (type) {
     case "system_icon":
       return coverSystemIconPart(origin);

+ 18 - 19
packages/qjkankan-editor/src/core/utils.js

@@ -98,9 +98,8 @@ export default class Utils {
     try {
       krpano.set("curscreen_x", krpano.get("stagewidth") / 2);
       krpano.set("curscreen_y", krpano.get("stageheight") / 2);
-      krpano.call(
-        "screentosphere(curscreen_x, curscreen_y, curscreen_ath, curscreen_atv);"
-      );
+      krpano.call("screentosphere(curscreen_x, curscreen_y, curscreen_ath, curscreen_atv);");
+
       const hotspot = convertJQHotspot(param);
       const hotspotStyle = Object.values(hotspot.style);
       const hotspotString = hotspotStyle.join("|");
@@ -110,17 +109,17 @@ export default class Utils {
       let icon = hotspot.icon.replace(/,/g, "|");
       let title = this.htmlEncode(hotspot.title);
       const callString = `addJQHotspot(
-        ${hotspot.id},
-        ${hotspot.type},
-        ${title},
-        "${icon}",
-        ${ath},
-        ${atv},
-        "${hotspot.link}",
-        ${hotspotSize},
-        ${hotspot.visible},
-        "${hotspotString}"
-        )`;
+          ${hotspot.id},
+          ${hotspot.type},
+          ${title},
+          "${icon}",
+          ${ath},
+          ${atv},
+          "${hotspot.link}",
+          ${hotspotSize},
+          ${hotspot.visible},
+          "${hotspotString}"
+          )`;
       krpano.call(callString);
     } catch (error) {
       console.error("error", error);
@@ -197,10 +196,7 @@ export default class Utils {
     } else if (window.location.pathname.indexOf("edit") > -1) {
       vue.$bus.emit("openHotspot", id);
     } else {
-      window.parent.postMessage(
-        { event: "hotspot", targetCode: sceneCode },
-        "*"
-      );
+      window.parent.postMessage({ event: "hotspot", targetCode: sceneCode }, "*");
     }
   }
 
@@ -217,7 +213,10 @@ export default class Utils {
       mysd = JSON.parse(someData);
     }
 
-    mysd.hotspots.forEach((item) => {
+    // mysd.hotspots.forEach((item) => {
+    //   this.addhotspot(krpano, item, type);
+    // });
+    mysd.forEach((item) => {
       this.addhotspot(krpano, item, type);
     });
   }

+ 50 - 2
packages/qjkankan-editor/src/framework/EditorHead.vue

@@ -38,11 +38,34 @@ export default {
 
       showPreview: false,
       canLoad: false,
+      hiddenSave: false,
     };
   },
 
   components: { preview },
-
+  watch: {
+    // "$route.name": {
+    //   immediate: true,
+    //   handler: function (newVal) {
+    //     if (newVal == "hotspot") {
+    //       // this.hiddenSave = true;
+    //     } else {
+    //       // this.hiddenSave = false;
+    //     }
+    //   },
+    // },
+    sceneList: {
+      handler: function (newVal, oldVal) {
+        if (newVal.length != oldVal.length) {
+          console.error("sceneList change");
+          this.$store.commit("base/ininDefaultData");
+          // this.$store.commit("screen/setVisualAngleList", state.sceneList);
+         
+        }
+      },
+      deep: true,
+    },
+  },
   mounted() {
     this.getSettingsInfo();
     this.$bus.on("canLoad", (data) => {
@@ -66,6 +89,7 @@ export default {
       catalogTopology: "catalogTopology",
       currentScene: "scene/currentScene",
       isEditing: "isEditing",
+      saveApiList: "scene/saveApiList",
     }),
 
     info() {
@@ -296,7 +320,28 @@ export default {
         $waiting.show();
 
         // console.error(this.$router.name)
-        this.$store.dispatch(`${this.$route.name}/save`);
+
+        if (this.saveApiList.length) {
+          let idx = this.saveApiList.find((item) => item == "navigation");
+          console.error(idx);
+          if (idx) {
+            //优先保存导航树
+            this.$store.dispatch(`navigation/save`).then((res) => {
+              this.saveApiList.forEach((item) => {
+                if (item != "navigation") {
+                  this.$store.dispatch(`${item}/save`);
+                }
+              });
+            });
+          } else {
+            this.saveApiList.forEach((item) => {
+              this.$store.dispatch(`${item}/save`);
+            });
+          }
+        } else {
+          this.$store.dispatch(`${this.$route.name}/save`).then((res) => {});
+        }
+
         // saveWorks(
         //   {
         //     password: this.info.password,
@@ -369,6 +414,9 @@ export default {
         (res) => {
           let data = res.data;
           this.$store.commit("base/initbaseInfo", data);
+
+          this.$store.commit("UpdateIsShowState", true);
+          // OnlineDetector.valid();
         },
         () => {}
       );

+ 2 - 6
packages/qjkankan-editor/src/framework/core/index.vue

@@ -6,9 +6,7 @@
     <div v-show="activeItem" id="pano"></div>
     <template v-if="showSnapshot && activeItem">
       <snapshot :showFlash="showFlash"></snapshot>
-      <button class="ui-button submit" @click="onClick">
-        将当前视角设为初始画面
-      </button>
+      <button class="ui-button submit" @click="onClick">将当前视角设为初始画面</button>
     </template>
   </div>
 </template>
@@ -45,9 +43,7 @@ export default {
   },
   methods: {
     updateInfo() {
-      let iidx = this.info.scenes.findIndex(
-        (item) => this.activeItem.sceneCode == item.sceneCode
-      );
+      let iidx = this.info.scenes.findIndex((item) => this.activeItem.sceneCode == item.sceneCode);
       if (iidx > -1) {
         this.info.scenes[iidx] = {
           ...this.activeItem,

+ 15 - 3
packages/qjkankan-editor/src/framework/play/pano/components/new-list.vue

@@ -1,19 +1,30 @@
 <template>
-  <div class="bar-list" v-if="info">
+  <div class="bar-list" v-if="info" :class="{ disable: isEditing }">
     <div class="top-con" v-show="currentScenesList.length">
       <div v-if="currentScenesList.length" class="scene-list swiper-container" ref="scene-swiper" :style="`width:${scenesListW > 1150 ? '100%' : scenesListW + 'px'}`">
         <!-- <div class="scene-list swiper-container" ref="scene-swiper"> -->
         <div class="swiper-wrapper scene-wrapper">
-          <div
+          <!-- <div
             class="swiper-slide scene-slide"
             :class="{
-              active: currentScene.id == item.id,
+              active: currentScene.id == item.id ||currentScene.id == item.sid  ,
               disabled: isLockV4Scene,
               // loopspan:
               //   item.sceneTitle.length > spanlength &&
               //   currentScene.id == item.id,
             }"
             v-for="(item, index) in currentScenesList"
+          > -->
+          <div
+            class="swiper-slide scene-slide"
+            :class="{
+              active: currentScene.id == item.id || (currentScene.sid && currentScene.sid == item.sid),
+              disabled: isLockV4Scene,
+              // loopspan:
+              //   item.sceneTitle.length > spanlength &&
+              //   currentScene.id == item.id,
+            }"
+            v-for="(item, index) in info.navigationTrees[rootTabIndex]?.children[secondTabIndex]?.children"
           >
             <div @click="tabCurrentScene(item, index)" class="scene-content" :style="`background-image:url(${item.icon});`">
               <!-- <img :src="i.icon" alt="" /> -->
@@ -145,6 +156,7 @@ export default {
       currentScenesList: "scene/currentScenesList",
       currentSecondId: "navigation/currentSecondId",
       currentRootId: "navigation/currentRootId",
+      isEditing: "isEditing",
     }),
     scenesListW() {
       return this?.currentScenesList?.length * (this.swidth["swScenes"] + 10) || 0;

+ 15 - 9
packages/qjkankan-editor/src/framework/play/pano/index.vue

@@ -36,6 +36,7 @@ import Snapshot from "@/components/Snapshot";
 import { uploadCover, searchInAll3DScenes } from "@/api";
 import config from "@/config";
 import { isUpgradeAdapter } from "@/utils/fixVersion";
+import hotspot from "@/Store/modules/hotspot";
 
 let __krfn = krfn.default;
 
@@ -59,6 +60,9 @@ export default {
       baseInfo: "base/baseInfo",
       isConfirmingPosi: "tags/isConfirmingPosi",
       sceneList: "base/sceneList",
+      hotspotList: "hotspot/hotspotList",
+      workVisualAngleList: "screen/workVisualAngleList",
+      workCustomMaskList: "mask/workCustomMaskList",
     }),
 
     showSnapshot() {
@@ -74,6 +78,7 @@ export default {
       this.handleRouterCoverForCap();
     },
     currentScene(newVal) {
+      console.error(newVal);
       if (newVal) {
         this.$nextTick(() => {
           this.$bus.emit("initView", newVal.icon);
@@ -104,7 +109,8 @@ export default {
         $("#pano").empty();
         window.vrInitFn = () => {
           $waiting.hide();
-          __krfn.utils.initHotspot(this.$getKrpano(), newVal && newVal.someData, true);
+          let hotspots = this.hotspotList.filter((item) => item.navigationId == this.currentScene.id);
+          __krfn.utils.initHotspot(this.$getKrpano(), hotspots, true);
           __krfn.utils.toggleHotspot(this.$getKrpano(), this.$route.name == "hotspot");
         };
         window.vrViewFn = () => {
@@ -112,11 +118,11 @@ export default {
             // let visual = newVal.initVisual;
             // const { sky, earth } = newVal.customMask;
 
-            let visual = this.baseInfo?.workVisualAngleList.find((item) => item.navigationId == newVal.id);
+            let visual = this.workVisualAngleList.find((item) => item.navigationId == newVal.id || item.navigationId == newVal.sid);
 
             let sky, earth;
-            this.baseInfo?.workCustomMaskList?.forEach((item, index) => {
-              if (this.currentScene.id == item.navigationId) {
+            this.workCustomMaskList.forEach((item, index) => {
+              if (this.currentScene.id == item.navigationId || this.currentScene.sid == item.navigationId) {
                 sky = item.data.sky;
                 earth = item.data.earth;
               }
@@ -191,14 +197,13 @@ export default {
           //   hlookat: data.hlookat,
           //   vlookat: data.vlookat,
           // };
-          this.baseInfo.workVisualAngleList.map((item) => {
-            if (item.navigationId == this.currentScene.id) {
+          this.workVisualAngleList.map((item) => {
+            if (item.navigationId == this.currentScene.id || item.navigationId == this.currentScene.sid) {
               item.hlookat = data.hlookat;
               item.vlookat = data.vlookat;
               item.icon = res.data;
             }
           });
-        
 
           // this.$store.commit("base/setData", { workVisualAngleList: this.baseInfo.workVisualAngleList });
 
@@ -275,8 +280,8 @@ export default {
         return;
       }
       let sky, earth;
-      this.baseInfo?.workCustomMaskList?.forEach((item, index) => {
-        if (this.currentScene.id == item.navigationId) {
+      this.workCustomMaskList.forEach((item, index) => {
+        if (this.currentScene.id == item.navigationId || this.currentScene.sid == item.navigationId) {
           sky = item.data.sky;
           earth = item.data.earth;
         }
@@ -321,6 +326,7 @@ export default {
     window.__krfn = __krfn;
 
     this.$bus.on("addhotspot", (data) => {
+      console.error("data", data);
       this.addhotspot(data);
     });
 

+ 1 - 1
packages/qjkankan-editor/src/framework/show/index.vue

@@ -293,7 +293,7 @@ export default {
             return;
           }
           if (newVal.hotspotType == "scene") {
-            this.activeItem = newVal.secne;
+            this.activeItem = newVal.scene;
             return;
           }
           this.showPreview = true;

+ 1 - 1
packages/qjkankan-editor/src/framework/showMobile/index.vue

@@ -378,7 +378,7 @@ export default {
             return;
           }
           if (newVal.hotspotType == "scene") {
-            this.activeItem = newVal.secne;
+            this.activeItem = newVal.scene;
             return;
           }
           if (newVal.hotspotType == "image") {

+ 5 - 4
packages/qjkankan-editor/src/pages/Edit.vue

@@ -68,12 +68,13 @@ export default {
       } else {
         return this.$alert({ content: "该作品已被删除" });
       }
-    });
-
-    getPanoInfo().then(() => {
-      this.$store.commit("UpdateIsShowState", true);
       OnlineDetector.valid();
     });
+
+    // getPanoInfo().then(() => {
+    //   this.$store.commit("UpdateIsShowState", true);
+    //   OnlineDetector.valid();
+    // });
   },
   mounted() {
     document.title = this.$i18n.t("gather.editpage_name");

+ 203 - 112
packages/qjkankan-editor/src/utils/other.js

@@ -1,27 +1,27 @@
 /**
  * 返回一个自带节流效果的函数,用res表示。
- * 
+ *
  * fn:需要被节流的函数
  * interval:最短多长时间允许执行一次fn
- * 
+ *
  * 功能要点:
  * 1.fn代码里如有this,res被执行时,this会指向res的调用者;
  * 2.res被执行时的实参会映射到fn的形参;
  * 3.第一次调用res时,会立即执行fn。
  */
 export function throttle(fn, interval) {
-  let lastRunTime = 0
+  let lastRunTime = 0;
 
   return function (...args) {
-    let elapsedTime = Date.now() - lastRunTime
+    let elapsedTime = Date.now() - lastRunTime;
     if (elapsedTime < interval) {
-      return
+      return;
     }
 
-    let context = this
-    lastRunTime = Date.now()
-    fn.apply(context, args)
-  }
+    let context = this;
+    lastRunTime = Date.now();
+    fn.apply(context, args);
+  };
 }
 
 /**
@@ -31,78 +31,81 @@ export function throttle(fn, interval) {
  * delay: 消抖时长
  * isImmediateCall: 是否在一组操作中的第一次调用时立即执行fn
  * isRememberLastCall:是否在一组中最后一次调用后等delay时长再执行fn
- * 
+ *
  * 如果isRememberLastCall为false,意味着fn不会被延迟执行,所以fnDebounced执行时,要么在内部调用fn,同步返回fn返回值;要么内部决定本次不调用fn,同步返回null。
  * 如果isRememberLastCall为true,意味着fn可能被延迟执行,所以fnDebounced会返回一个Promise,在fn被调用时用其返回值resolve该Promise,或者在fn的延时调用计划被取消时用'canceled'resolve该Promise。(不宜reject,否则又没有人去catch,会导致浏览器报错。)
  */
 export function debounce(fn, delay = 250, isImmediateCall = false, isRememberLastCall = true) {
-  console.assert(isImmediateCall || isRememberLastCall, 'isImmediateCall 和 isRememberLastCall 至少应有一个是true,否则没有意义!')
-  let timer = null
-  let retPromiseLastTimeResolver = null
+  console.assert(isImmediateCall || isRememberLastCall, "isImmediateCall 和 isRememberLastCall 至少应有一个是true,否则没有意义!");
+  let timer = null;
+  let retPromiseLastTimeResolver = null;
   // 上次调用的时刻
-  let lastCallTime = 0
+  let lastCallTime = 0;
 
   if (isImmediateCall && !isRememberLastCall) {
     return function (...args) {
-      let ret = null
-      const currentTime = Date.now()
+      let ret = null;
+      const currentTime = Date.now();
       if (currentTime - lastCallTime >= delay) {
-        ret = fn.apply(this, args)
+        ret = fn.apply(this, args);
       }
-      lastCallTime = currentTime
-      return ret
-    }
+      lastCallTime = currentTime;
+      return ret;
+    };
   } else if (!isImmediateCall && isRememberLastCall) {
     return function (...args) {
       if (timer) {
-        clearTimeout(timer)
-        timer = null
+        clearTimeout(timer);
+        timer = null;
       }
       if (retPromiseLastTimeResolver) {
-        retPromiseLastTimeResolver('canceled')
-        retPromiseLastTimeResolver = null
+        retPromiseLastTimeResolver("canceled");
+        retPromiseLastTimeResolver = null;
       }
       const ret = new Promise((resolve, reject) => {
-        retPromiseLastTimeResolver = resolve
+        retPromiseLastTimeResolver = resolve;
         timer = setTimeout(() => {
-          timer = null
-          retPromiseLastTimeResolver = null
-          resolve(fn.apply(this, args))
-        }, delay)
-      })
-      return ret
-    }
+          timer = null;
+          retPromiseLastTimeResolver = null;
+          resolve(fn.apply(this, args));
+        }, delay);
+      });
+      return ret;
+    };
   } else if (isImmediateCall && isRememberLastCall) {
     return function (...args) {
-      const currentTime = Date.now()
-      if (currentTime - lastCallTime >= delay) { // 一组操作中的第一次
-        const res = fn.apply(this, args)
-        lastCallTime = currentTime
-        return Promise.resolve(res)
-      } else { // 一组中的后续调用
-        if (timer) { // 在此之前存在中间调用
-          lastCallTime = currentTime
-          clearTimeout(timer)
-          timer = null
+      const currentTime = Date.now();
+      if (currentTime - lastCallTime >= delay) {
+        // 一组操作中的第一次
+        const res = fn.apply(this, args);
+        lastCallTime = currentTime;
+        return Promise.resolve(res);
+      } else {
+        // 一组中的后续调用
+        if (timer) {
+          // 在此之前存在中间调用
+          lastCallTime = currentTime;
+          clearTimeout(timer);
+          timer = null;
         }
         if (retPromiseLastTimeResolver) {
-          retPromiseLastTimeResolver('canceled')
-          retPromiseLastTimeResolver = null
+          retPromiseLastTimeResolver("canceled");
+          retPromiseLastTimeResolver = null;
         }
         const ret = new Promise((resolve, reject) => {
-          retPromiseLastTimeResolver = resolve
+          retPromiseLastTimeResolver = resolve;
           timer = setTimeout(() => {
-            lastCallTime = 0
-            timer = null
-            retPromiseLastTimeResolver = null
-            resolve(fn.apply(this, args))
-          }, delay)
-        })
-        return ret
+            lastCallTime = 0;
+            timer = null;
+            retPromiseLastTimeResolver = null;
+            resolve(fn.apply(this, args));
+          }, delay);
+        });
+        return ret;
       }
-    }
+    };
   } else {
-    console.error('不应该执行到这里!')
+    console.error("不应该执行到这里!");
   }
 }
 
@@ -123,116 +126,116 @@ export function debounce(fn, delay = 250, isImmediateCall = false, isRememberLas
 ④12345678
  */
 export function isValidPhoneNumber(value) {
-  const reg = /^1\d{10}$|^400[0-9]{7}|^(0\d{2,3}-?|\(0\d{2,3}\))?[1-9]\d{4,7}(-\d{1,8})?$/
+  const reg = /^1\d{10}$|^400[0-9]{7}|^(0\d{2,3}-?|\(0\d{2,3}\))?[1-9]\d{4,7}(-\d{1,8})?$/;
   // const reg = /^400[0-9]{7}|^1[34578]\d{9}$|^0[0-9]{2,3}-[0-9]{8}/
 
-  return reg.test(value)
+  return reg.test(value);
 }
 
 // 深拷贝,为了解决循环引用和共同引用的问题,引入了WeakMap,又因为引入WeakMap可能会导致被拷贝对象被挂上【作为WeakMap的探针的】匿名函数(是pollyfill的行为吧?),所以不会拷贝非根元素的匿名函数。
 export function deepClone(target, hash = new WeakMap()) {
   // 定义一个变量
-  let result = null
+  let result = null;
   // 如果当前需要深拷贝的是一个对象的话
-  if (typeof target === 'object') {
-    if (hash.has(target)) { // 如果是循环引用
-      result = hash.get(target)
-    } else if (Array.isArray(target)) { // 如果是一个数组的话
-      result = [] // 将result赋值为一个数组,并且执行遍历
-      hash.set(target, result)
+  if (typeof target === "object") {
+    if (hash.has(target)) {
+      // 如果是循环引用
+      result = hash.get(target);
+    } else if (Array.isArray(target)) {
+      // 如果是一个数组的话
+      result = []; // 将result赋值为一个数组,并且执行遍历
+      hash.set(target, result);
       for (let i in target) {
-        if (!(typeof (target[i]) === 'function' && !target.name)) {
+        if (!(typeof target[i] === "function" && !target.name)) {
           // 递归克隆数组中的每一项
-          result.push(deepClone(target[i], hash))
+          result.push(deepClone(target[i], hash));
         }
       }
       // 判断如果当前的值是null的话;直接赋值为null
     } else if (target === null) {
-      result = null
+      result = null;
       // 判断如果当前的值是一个RegExp对象的话,直接赋值
     } else if (target.constructor === RegExp) {
-      result = target
+      result = target;
     } else {
       // 否则是普通对象,直接for in循环,递归赋值对象的所有值
-      result = {}
-      hash.set(target, result)
+      result = {};
+      hash.set(target, result);
       for (let i in target) {
-        if (!(typeof (target[i]) === 'function' && !target.name)) {
-          result[i] = deepClone(target[i], hash)
+        if (!(typeof target[i] === "function" && !target.name)) {
+          result[i] = deepClone(target[i], hash);
         }
       }
     }
-  } else if (typeof target === 'function') {
-    result = target
-  } else { // 如果不是对象也不是函数,直接赋值
-    result = target
+  } else if (typeof target === "function") {
+    result = target;
+  } else {
+    // 如果不是对象也不是函数,直接赋值
+    result = target;
   }
   // 返回最终结果
-  return result
+  return result;
 }
 
 export function isObjectBroad(p) {
-  return typeof (p) === 'object' || typeof (p) === 'function'
+  return typeof p === "object" || typeof p === "function";
 }
 
 // 判断两个对象内容是否相同。未考虑循环引用、共同引用的情况。
 export function isSameObject(object1, object2) {
-  const keys1 = Object.keys(object1)
-  const keys2 = Object.keys(object2)
+  const keys1 = Object.keys(object1);
+  const keys2 = Object.keys(object2);
 
   if (keys1.length !== keys2.length) {
-    return false
+    return false;
   }
 
   for (let index = 0; index < keys1.length; index++) {
-    const val1 = object1[keys1[index]]
-    const val2 = object2[keys2[index]]
-    const areObjects = isObjectBroad(val1) && isObjectBroad(val2)
-    if (
-      (areObjects && !isSameObject(val1, val2)) ||
-      (!areObjects && (val1 !== val2))
-    ) {
-      return false
+    const val1 = object1[keys1[index]];
+    const val2 = object2[keys2[index]];
+    const areObjects = isObjectBroad(val1) && isObjectBroad(val2);
+    if ((areObjects && !isSameObject(val1, val2)) || (!areObjects && val1 !== val2)) {
+      return false;
     }
   }
-  return true
+  return true;
 }
 
 export function ossImagePreviewUrlSuffix(downScaleRate = 10) {
-  return `?x-oss-process=image/resize,p_${downScaleRate}&${Math.random()}`
+  return `?x-oss-process=image/resize,p_${downScaleRate}&${Math.random()}`;
 }
 
 export function postOrderTraversal(root, routine) {
   if (root.children && Array.isArray(root.children)) {
     for (const child of root.children) {
-      postOrderTraversal(child, routine)
+      postOrderTraversal(child, routine);
     }
   }
-  routine(root)
+  routine(root);
 }
 
 export function preOrderTraversalSearch(root, checkNode, targetNodePath) {
-  console.assert(root && checkNode && targetNodePath, `param invalid: ${root} ${checkNode} ${targetNodePath}`)
-  targetNodePath.push(root)
-  let rootCheckRes = checkNode(root)
+  console.assert(root && checkNode && targetNodePath, `param invalid: ${root} ${checkNode} ${targetNodePath}`);
+  targetNodePath.push(root);
+  let rootCheckRes = checkNode(root);
   if (rootCheckRes) {
-    return true
+    return true;
   }
   if (root.children && Array.isArray(root.children)) {
     for (const child of root.children) {
-      let childCheckRes = preOrderTraversalSearch(child, checkNode, targetNodePath)
+      let childCheckRes = preOrderTraversalSearch(child, checkNode, targetNodePath);
       if (childCheckRes) {
-        return true
+        return true;
       }
     }
   }
-  targetNodePath.pop()
-  return false
+  targetNodePath.pop();
+  return false;
 }
 export function nodeIdList2nodeInfoListByNodeTree(nodeIdList, nodeTree) {
-  nodeIdList = nodeIdList.filter(i => i);
+  nodeIdList = nodeIdList.filter((i) => i);
   if (nodeIdList.length === 0) {
-    return null
+    return null;
   }
 
   // console.log('nodeIdList', nodeIdList)
@@ -242,27 +245,115 @@ export function nodeIdList2nodeInfoListByNodeTree(nodeIdList, nodeTree) {
     {
       id: nodeTree.id,
       name: nodeTree.name,
-    }
-  ]
+    },
+  ];
   if (nodeIdList[1] || nodeIdList[1] === 0) {
     // console.assert(nodeTree.children && nodeTree.children.length > 0, 'nodeIdList2nodeInfoListByNodeTree: 不可能的任务2!')
     const nextLevelRoot = nodeTree.children.find((item) => {
-      return item.id === nodeIdList[1]
-    })
+      return item.id === nodeIdList[1];
+    });
     // console.log('nextLevelRoot', nextLevelRoot)
     // console.assert(nextLevelRoot, 'nodeIdList2nodeInfoListByNodeTree: invalid param 2!')
-    ret = ret.concat(nodeIdList2nodeInfoListByNodeTree(nodeIdList.slice(1, nodeIdList.length), nextLevelRoot))
+    ret = ret.concat(nodeIdList2nodeInfoListByNodeTree(nodeIdList.slice(1, nodeIdList.length), nextLevelRoot));
   }
 
-  return ret
+  return ret;
 }
 
 export function capitalize(str) {
   if (!str) {
-    return
+    return;
   }
   if (str.length === 1) {
-    return str[0].toUpperCase()
+    return str[0].toUpperCase();
+  }
+  return str[0].toUpperCase() + str.slice(1, str.length);
+}
+
+export function getRandomSid() {
+  //5-7位随机字符串 + 6位时间    为热点准备
+  var pre = randomWord(true, 5, 7);
+  var post = new Date().getTime() + "";
+  var len = post.length;
+  post = post.substring(len - 8, len - 5) + post.substring(len - 3, len); //其实还是有可能重复的....
+  return pre + post;
+}
+function randomWord(randomFlag, min, max) {
+  //随机字符串
+  var str = "",
+    range = min,
+    arr = [
+      "0",
+      "1",
+      "2",
+      "3",
+      "4",
+      "5",
+      "6",
+      "7",
+      "8",
+      "9",
+      "a",
+      "b",
+      "c",
+      "d",
+      "e",
+      "f",
+      "g",
+      "h",
+      "i",
+      "j",
+      "k",
+      "l",
+      "m",
+      "n",
+      "o",
+      "p",
+      "q",
+      "r",
+      "s",
+      "t",
+      "u",
+      "v",
+      "w",
+      "x",
+      "y",
+      "z",
+      "A",
+      "B",
+      "C",
+      "D",
+      "E",
+      "F",
+      "G",
+      "H",
+      "I",
+      "J",
+      "K",
+      "L",
+      "M",
+      "N",
+      "O",
+      "P",
+      "Q",
+      "R",
+      "S",
+      "T",
+      "U",
+      "V",
+      "W",
+      "X",
+      "Y",
+      "Z",
+    ];
+
+  if (randomFlag) {
+    // 随机长度
+    range = Math.round(Math.random() * (max - min)) + min;
   }
-  return str[0].toUpperCase() + str.slice(1, str.length)
-}
+  for (var i = 0; i < range; i++) {
+    var pos = Math.round(Math.random() * (arr.length - 1));
+    str += arr[pos];
+  }
+  return str;
+}

+ 24 - 66
packages/qjkankan-editor/src/views/base/Toolbar.vue

@@ -9,25 +9,13 @@
         <div class="upload-con">
           <div class="uc-l">
             <div class="preview">
-              <img
-                :src="
-                  info.work.icon ||
-                  require('@/assets/images/default/img_cover_default_2.png')
-                "
-                alt=""
-              />
-        
-              <button
-                class="ui-button submit setting-cover-btn"
-                @click="onClickSettingCover"
-              >
+              <img :src="info.work.icon || require('@/assets/images/default/img_cover_default_2.png')" alt="" />
+
+              <button class="ui-button submit setting-cover-btn" @click="onClickSettingCover">
                 {{ $i18n.t(`edit_settings.setting_cover`) }}
               </button>
             </div>
-            <div
-              class="ui-remark"
-              v-html="$i18n.t(`edit_settings.cover_size`)"
-            ></div>
+            <div class="ui-remark" v-html="$i18n.t(`edit_settings.cover_size`)"></div>
           </div>
           <div class="uc-r">
             <div class="ui-title">
@@ -56,13 +44,7 @@
               type="text"
             /> -->
 
-              <editor
-                ref="editor"
-                :html="info.work.description"
-                :placeholder="$i18n.t(`edit_settings.intro_placeholder`)"
-                :maxlength="2000"
-                @change="onEditorChange"
-              ></editor>
+              <editor ref="editor" :html="info.work.description" :placeholder="$i18n.t(`edit_settings.intro_placeholder`)" :maxlength="2000" @change="onEditorChange"></editor>
 
               <span class="count">{{ introLength }}/2000</span>
             </div>
@@ -71,53 +53,29 @@
       </div>
       <div class="bottom-container">
         <menu>
-          <li
-            v-for="item in tabs"
-            :key="item"
-            :class="{ active: activeTab === item }"
-            @click="activeTab = item"
-          >
+          <li v-for="item in tabs" :key="item" :class="{ active: activeTab === item }" @click="activeTab = item">
             {{ $i18n.t(`baseSetting.${item}`) }}
           </li>
         </menu>
 
         <div class="settings-view-wrapper">
-          <OpeningTipSettings
-            v-show="activeTab === 'openTips'"
-          ></OpeningTipSettings>
-          <OpeningAnimationSettings
-            v-show="activeTab === 'openAnimate'"
-          ></OpeningAnimationSettings>
-          <PasswordSettings
-            v-show="activeTab === 'password'"
-          ></PasswordSettings>
-          <AutoCruiseSettings
-            v-show="activeTab === 'cruise'"
-          ></AutoCruiseSettings>
-          <BackgroundMusicSettings
-            v-show="activeTab === 'bgm'"
-          ></BackgroundMusicSettings>
-          <CustomLogoSettings
-            v-show="activeTab === 'logo'"
-          ></CustomLogoSettings>
+          <OpeningTipSettings v-show="activeTab === 'openTips'"></OpeningTipSettings>
+          <OpeningAnimationSettings v-show="activeTab === 'openAnimate'"></OpeningAnimationSettings>
+          <PasswordSettings v-show="activeTab === 'password'"></PasswordSettings>
+          <AutoCruiseSettings v-show="activeTab === 'cruise'"></AutoCruiseSettings>
+          <BackgroundMusicSettings v-show="activeTab === 'bgm'"></BackgroundMusicSettings>
+          <CustomLogoSettings v-show="activeTab === 'logo'"></CustomLogoSettings>
           <!-- <CustomMaskSettings
             v-show="activeTab === 'customCover'"
           ></CustomMaskSettings> -->
-          <CustomButtonSettings
-            v-show="activeTab === 'customButton'"
-          ></CustomButtonSettings>
+          <CustomButtonSettings v-show="activeTab === 'customButton'"></CustomButtonSettings>
           <CoverBase v-show="activeTab === 'openCover'"></CoverBase>
         </div>
       </div>
     </div>
 
     <div class="dialog" style="z-index: 2000" v-if="isShowSettingCoverWindow">
-      <MaterialSelector
-        :selectableType="['image', 'pano', '3D']"
-        :title="$i18n.t(`gather.select_material`)"
-        @cancel="isShowSettingCoverWindow = false"
-        @submit="onCoverSelected"
-      />
+      <MaterialSelector :selectableType="['image', 'pano', '3D']" :title="$i18n.t(`gather.select_material`)" @cancel="isShowSettingCoverWindow = false" @submit="onCoverSelected" />
     </div>
   </div>
 </template>
@@ -135,6 +93,7 @@ import CustomMaskSettings from "@/views/base/customMaskSettings.vue";
 import CustomButtonSettings from "@/views/base/customButtonSettings.vue";
 import Editor from "@/components/shared/Editor";
 import CoverBase from "@/views/base/coverBase.vue";
+import { deepClone, isSameObject } from "@/utils/other.js";
 
 export default {
   components: {
@@ -190,19 +149,18 @@ export default {
     },
   },
   mounted() {},
-  watch: {},
+  watch: {
+  
+  },
   methods: {
     emojistr() {
-      this.info.work.name = this.info.work.name.replace(
-        /(\ud83c[\udf00-\udfff])|(\ud83d[\udc00-\ude4f])|(\ud83d[\ude80-\udeff])/g,
-        function (char) {
-          if (char.length === 2) {
-            return "";
-          } else {
-            return char;
-          }
+      this.info.work.name = this.info.work.name.replace(/(\ud83c[\udf00-\udfff])|(\ud83d[\udc00-\ude4f])|(\ud83d[\ude80-\udeff])/g, function (char) {
+        if (char.length === 2) {
+          return "";
+        } else {
+          return char;
         }
-      );
+      });
     },
     onEditorChange(content) {
       this.info.work.description = content.html;

+ 12 - 25
packages/qjkankan-editor/src/views/base/index.vue

@@ -8,7 +8,7 @@
 <script>
 import Toolbar from "./Toolbar";
 import { mapGetters } from "vuex";
-import { getWorkInfo } from "@/api";
+import { deepClone, isSameObject } from "@/utils/other.js";
 export default {
   name: "EditorBase",
   components: {
@@ -26,32 +26,19 @@ export default {
     }),
   },
   watch: {
-    // info: {
-    //   handler(newVal, oldVal) {
-    //     if (newVal && !this.isInit) {
-    //       this.isInit = true;
-    //       this.getSettingsInfo();
-    //     }
-    //   },
-    // },
-  },
-
-  methods: {
-    getSettingsInfo() {
-      // this.$store.commit("base/setData", this.info);
-      getWorkInfo(
-        {},
-        (res) => {
-          let data = res.data;
-          this.$store.commit("base/initbaseInfo", data);
-        },
-        () => {}
-      );
+    info: {
+      handler(newVal, oldVal) {
+        if (newVal && this.$route.name == "base") {
+          console.error("base change");
+          this.$store.commit("scene/setSaveApiList", "base");
+        }
+      },
+      deep: true,
     },
   },
-  mounted() {
-    // this.getSettingsInfo();
-  },
+
+  methods: {},
+  mounted() {},
 };
 </script>
 

+ 11 - 3
packages/qjkankan-editor/src/views/explanation/explanationSettings.vue

@@ -29,8 +29,6 @@
       </template>
 
       <div class="switch-wrapper">
-
-
         <span class="label">{{ $i18n.t("explanation.default_open") }}</span>
         <Switcher :disable="!currentScene || currentScene.type === '4dkk'" :value="currentExplanation.openByDefault" @change="currentExplanation.openByDefault = !currentExplanation.openByDefault" />
       </div>
@@ -71,9 +69,10 @@ export default {
     ...mapGetters({
       baseInfo: "base/baseInfo",
       currentScene: "scene/currentScene",
+      workExplanationList: "explanation/workExplanationList",
     }),
     currentExplanation() {
-      return this.baseInfo.workExplanationList.find((item) => item.navigationId == this.currentScene.id);
+      return this.workExplanationList.find((item) => item.navigationId == this.currentScene.id ||  item.navigationId == this.currentScene.sid);
     },
   },
   data() {
@@ -100,6 +99,15 @@ export default {
     },
   },
   watch: {
+    baseInfo: {
+      handler(newVal, oldVal) {
+        if (newVal && this.$route.name == "explanation") {
+          console.error("explanation change");
+          this.$store.commit("scene/setSaveApiList", "explanation");
+        }
+      },
+      deep: true,
+    },
     // currentScene: {
     //   immediate: true,
     //   handler: function (newVal) {

+ 45 - 101
packages/qjkankan-editor/src/views/hotspot/EditPanel.vue

@@ -1,10 +1,5 @@
 <template>
-  <transition
-    appear
-    name="custom-classes-transition"
-    enter-active-class="animated slideInRight speed"
-    leave-active-class="animated slideOutRight speed"
-  >
+  <transition appear name="custom-classes-transition" enter-active-class="animated slideInRight speed" leave-active-class="animated slideOutRight speed">
     <div class="hots-panel" v-show="show">
       <div class="ui-between header">
         <span>{{ editTitle }}{{ $i18n.t("hotspot.hotspot_name") }}</span>
@@ -14,39 +9,19 @@
       <div class="content" ref="content">
         <div class="type-setting">
           <div class="remark">{{ $i18n.t("hotspot.hotspot_type") }}</div>
-          <combox
-            class="combox"
-            :data="hotspotTypeList"
-            :selected-id="hotspot.hotspotType"
-            @change="onHotSpotTypeChange"
-          />
+          <combox class="combox" :data="hotspotTypeList" :selected-id="hotspot.hotspotType" @change="onHotSpotTypeChange" />
         </div>
 
         <div class="icon-setting">
           <div class="remark">{{ $i18n.t("hotspot.hotspot_icon") }}</div>
-          <combox
-            class="combox"
-            :data="hotspotIconTypeList"
-            :selected-id="hotspot.hotspotIconType"
-            @change="onHotspotIconTypeChange"
-          />
-          <component
-            class="icon-setting-component"
-            :is="iconTypeComponent"
-            ref="icon-setting-component"
-          />
-          <div
-            class="bars"
-            v-if="hotspot.hotspotIconType !== 'personalized_tag'"
-          >
+          <combox class="combox" :data="hotspotIconTypeList" :selected-id="hotspot.hotspotIconType" @change="onHotspotIconTypeChange" />
+          <component class="icon-setting-component" :is="iconTypeComponent" ref="icon-setting-component" />
+          <div class="bars" v-if="hotspot.hotspotIconType !== 'personalized_tag'">
             <RangeItem :value="rang" @input="onRangeChange" />
           </div>
         </div>
 
-        <div
-          class="title-setting"
-          v-if="hotspot.hotspotIconType !== 'personalized_tag'"
-        >
+        <div class="title-setting" v-if="hotspot.hotspotIconType !== 'personalized_tag'">
           <div class="remark-highlight">
             {{ $i18n.t("hotspot.hotspot_title") }}
           </div>
@@ -55,10 +30,7 @@
             <div class="remark">
               {{ $i18n.t("hotspot.show_hotspot_title") }}
             </div>
-            <Switcher
-              :value="tempHotpotLabelShow"
-              @change="onSwitcherChange"
-            ></Switcher>
+            <Switcher :value="tempHotpotLabelShow" @change="onSwitcherChange"></Switcher>
           </div>
 
           <!-- <div class="title-input-wrapper">
@@ -128,19 +100,8 @@
 
         <div class="effect-setting">
           <div class="title-line">
-            <div
-              class="remark-highlight"
-              v-if="
-                $i18n.t(
-                  `hotspot.hotspot_type_specific_settings_title.${hotspot.hotspotType}`
-                )
-              "
-            >
-              {{
-                $i18n.t(
-                  `hotspot.hotspot_type_specific_settings_title.${hotspot.hotspotType}`
-                )
-              }}
+            <div class="remark-highlight" v-if="$i18n.t(`hotspot.hotspot_type_specific_settings_title.${hotspot.hotspotType}`)">
+              {{ $i18n.t(`hotspot.hotspot_type_specific_settings_title.${hotspot.hotspotType}`) }}
             </div>
             <div class="tip" v-if="currentHotspotTypeConfigData.tip">
               {{ currentHotspotTypeConfigData.tip }}
@@ -149,7 +110,7 @@
           <component
             class="effect-setting-component"
             @sceneSelect="handleSceneSelect"
-            :scene="hotspot.secne"
+            :scene="hotspot.scene"
             @imageChange="
               (data) => {
                 hotspot.image = data;
@@ -191,19 +152,12 @@
         </div>
       </div>
       <div class="ui-between footer" app-border dir-top>
-        <button
-          class="ui-button deepcancel"
-          :class="{ disable: false }"
-          @click="realCancel"
-        >
+        <button class="ui-button deepcancel" :class="{ disable: false }" @click="realCancel">
           {{ $i18n.t("hotspot.cancel") }}
         </button>
-        <button
-          class="ui-button submit"
-          :class="{ disable: !canSubmit }"
-          @click="save"
-        >
-          {{ $i18n.t("hotspot.finish") }}
+        <button class="ui-button submit" :class="{ disable: !canSubmit }" @click="save">
+          <!-- {{ $i18n.t("hotspot.finish") }} -->
+          {{ $i18n.t("edit_page.save") }}
         </button>
       </div>
     </div>
@@ -268,12 +222,14 @@ export default {
     "hotspot.titleDisplayMode": {
       handler(val) {
         console.log("titleDisplayMode", val);
-        if (val === "always") {
-          this.tempHotpotLabelShow = 1;
-        }
-        if (val === "never") {
-          this.tempHotpotLabelShow = 0;
-        }
+        // if (val === "always") {
+        //   this.tempHotpotLabelShow = 1;
+        // }
+        // if (val === "never") {
+        //   this.tempHotpotLabelShow = 0;
+        // }
+
+        this.tempHotpotLabelShow = val;
       },
       immediate: true,
     },
@@ -358,9 +314,9 @@ export default {
   },
   computed: {
     ...mapGetters({
-      hotspot: "hotspot",
+      hotspot: "hotspot/hotspot",
       backupHotSpot: "backupHotSpot",
-      hotspotIcon: "hotspotIcon",
+      hotspotIcon: "hotspot/hotspotIcon",
     }),
     iconTypeComponent() {
       let tmp = this.hotspot.hotspotIconType;
@@ -402,7 +358,7 @@ export default {
       // 热点类型相关设置项
       switch (this.hotspot.hotspotType) {
         case "scene":
-          if (!(this.hotspot.secne && this.hotspot.secne.id)) {
+          if (!(this.hotspot.scene && this.hotspot.scene.id)) {
             return false;
           }
           break;
@@ -434,10 +390,7 @@ export default {
         case "tag":
           break;
         case "imageText":
-          if (
-            this.hotspot.imageTextInfo.imageList.length === 0 ||
-            this.hotspot.imageTextInfo.text.length === 0
-          ) {
+          if (this.hotspot.imageTextInfo.imageList.length === 0 || this.hotspot.imageTextInfo.text.length === 0) {
             return false;
           }
 
@@ -471,18 +424,12 @@ export default {
           }
           break;
         case "serial_frame":
-          if (
-            !this.hotspot.serialFrameInfo.img ||
-            this.hotspot.serialFrameInfo.img.length === 0
-          ) {
+          if (!this.hotspot.serialFrameInfo.img || this.hotspot.serialFrameInfo.img.length === 0) {
             return false;
           }
           break;
         case "personalized_tag":
-          if (
-            this.hotspot.personalizedTagInfo.isTextWrap &&
-            this.hotspot.personalizedTagInfo.textNumPerLine <= 0
-          ) {
+          if (this.hotspot.personalizedTagInfo.isTextWrap && this.hotspot.personalizedTagInfo.textNumPerLine <= 0) {
             return false;
           }
           break;
@@ -515,10 +462,7 @@ export default {
     this.$bus.on("edithotspot", this.handleEditHotspot);
 
     setTimeout(() => {
-      if (
-        this.editTitle != "编辑" &&
-        this.editTitle != this.$i18n.t("hotspot.edit")
-      ) {
+      if (this.editTitle != "编辑" && this.editTitle != this.$i18n.t("hotspot.edit")) {
         this.rang.value = window.g_hotspotCurrentScale;
         this.onRangeChange({ value: window.g_hotspotCurrentScale });
       }
@@ -527,16 +471,17 @@ export default {
 
   methods: {
     handleEditHotspot(data) {
+      console.error("handleEditHotspot");
       const krpano = document.getElementById("krpanoSWFObject");
       __krfn.utils.edithotspot(krpano, data);
     },
     handleSceneSelect(data) {
-     
-      this.hotspot.secne = {
+      this.hotspot.scene = {
         ...data,
-        someData: {},
+        // someData: {},
       };
-  
+      // this.hotspot.content.scene = data;
+      console.error(this.hotspot);
     },
     onHotSpotTypeChange(data) {
       this.hotspot.hotspotType = data.id;
@@ -621,10 +566,7 @@ export default {
       }
     },
     listerFnReset() {
-      if (
-        this.hotspot.hotspotTitle == "单击确定热点位置" ||
-        this.hotspot.hotspotTitle == this.$i18n.t("hotspot.click_to_comfirm")
-      ) {
+      if (this.hotspot.hotspotTitle == "单击确定热点位置" || this.hotspot.hotspotTitle == this.$i18n.t("hotspot.click_to_comfirm")) {
         this.hotspot.hotspotTitle = "";
       }
     },
@@ -642,11 +584,9 @@ export default {
       // }
     },
     realCancel() {
-      this.$store.commit("SetHotspot", this.backupHotSpot);
+      this.$store.commit("hotspot/SetHotspot", this.backupHotSpot);
       console.log("cancel", this.backupHotSpot);
-      this.$getKrpano().call(
-        "cancelJQHotspot(" + this.backupHotSpot.name + ");"
-      );
+      this.$getKrpano().call("cancelJQHotspot(" + this.backupHotSpot.name + ");");
       this.$emit("close", {
         type: this.editTitle == this.$i18n.t("hotspot.edit") ? "edit" : "add",
         data: this.backupHotSpot,
@@ -661,17 +601,21 @@ export default {
       // this.$store.commit("SetHotspot", this.hotspot);
       // this.$emit("close");
       // this.$emit("save", this.hotspot);
-      console.error(this.hotspot)
-      this.$store.dispatch('hotspot/save',this.hotspot)
+      // this.$store.dispatch("hotspot/save", this.hotspot);
+
+      this.$store.commit("hotspot/updateHotspot", this.hotspot);
+      this.$store.commit("scene/setSaveApiList", "hotspot");
+      this.$emit("close");
     },
     onSwitcherChange(val) {
       console.log("onSwitcherChange", val);
       this.tempHotpotLabelShow = val;
       if (val === 0) {
-        this.hotspot.titleDisplayMode = "never";
+        // this.hotspot.titleDisplayMode = "never";
+        this.hotspot.titleDisplayMode = 0;
       }
       if (val === 1) {
-        this.hotspot.titleDisplayMode = "always";
+        this.hotspot.titleDisplayMode = 1;
       }
     },
   },

+ 133 - 48
packages/qjkankan-editor/src/views/hotspot/HotSpotList.vue

@@ -27,11 +27,12 @@
 
       <div class="total-count">
         {{ $i18n.t("hotspot.current_hotspots") }}
-        <span class="number">({{ someData.hotspots.length }})</span>
+        <span class="number">({{ currentHotsopts.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)">
+        <!-- <ul v-if="someData.hotspots.length > 0"> -->
+        <ul v-if="currentHotsopts.length > 0">
+          <li v-for="(item, key) in currentHotsopts" :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="$i18n.t('hotspot.delete')" @click.stop="deleIndex = key" />
@@ -95,8 +96,12 @@ export default {
   computed: {
     ...mapGetters({
       currentScene: "scene/currentScene",
-      hotspot: "hotspot",
-      info: "info",
+      hotspot: "hotspot/hotspot",
+      // info: "info",
+      baseInfo: "base/baseInfo",
+      hotspotList: "hotspot/hotspotList",
+      isConfirmingPosi: "tags/isConfirmingPosi",
+      currentHotsopts: "hotspot/currentHotsopts",
     }),
     experience_icon() {
       const lang = browser.urlQueryValue("lang");
@@ -106,54 +111,81 @@ export default {
         return require("@/assets/img/experience_zh.png");
       }
     },
+    // currentHotsopts() {
+    //   console.error('currentHotsopts', this.hotspotList)
+    //   return this.hotspotList.filter((item) => item.navigationId == this.currentScene.id || item.navigationId == this.currentScene.sid);
+    // },
   },
   watch: {
     "$route.name": function () {
       this.showPanel = false;
     },
+
+    hotspotList: {
+      handler(newVal, oldVal) {
+        if (newVal && this.$route.name == "hotspot") {
+          console.error("hotspot change");
+          this.$store.commit("scene/setSaveApiList", "hotspot");
+        }
+      },
+      deep: true,
+    },
     currentScene: {
       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: [] };
-        }
+        // 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: [] };
+        // }
       },
     },
     showPanel(newVal) {
       this.$store.commit("UpdateIsEditingState", newVal);
-      this.$store.commit("tags/setIsConfirmingPosi", false);
+      if (!newVal) {
+        this.$store.commit("tags/setIsConfirmingPosi", false);
+      }
     },
   },
   mounted() {
     this.$bus.on("updateHotSpotHV", (data) => {
-      let hptarget = this.someData.hotspots.find((item) => item.name.toLowerCase() == data.hpname.toLowerCase());
+      console.error("updateHotSpotHV", data);
+      // let hptarget = this.someData.hotspots.find((item) => item.name.toLowerCase() == data.hpname.toLowerCase());
+
+      let hptarget = this.hotspotList.findIndex((item) => item.name.toLowerCase() == data.hpname.toLowerCase());
+      if (data.hpname.toLowerCase() == this.hotspot.name.toLowerCase()) {
+        //兼容新增
+        this.hotspot.ath = data.ath;
+        this.hotspot.atv = data.atv;
+      }
       if (hptarget) {
-        console.log("hptarget", hptarget);
-        hptarget.ath = data.ath;
-        hptarget.atv = data.atv;
+        this.hotspotList[hptarget].ath = data.ath;
+        this.hotspotList[hptarget].atv = data.atv;
+        console.log("hptarget", this.hotspotList[hptarget]);
       }
     });
 
     this.$bus.on("openHotspot", (data) => {
-      let idx = this.someData.hotspots.findIndex((item) => item.name.toLowerCase() == data.toLowerCase());
+      console.error("openHotspot", data);
+      // let idx = this.someData.hotspots.findIndex((item) => item.name.toLowerCase() == data.toLowerCase());
+      console.error(this.hotspotList[2].name.toLowerCase(), data.toLowerCase());
+      let idx = this.hotspotList.findIndex((item) => item.name.toLowerCase() == data.toLowerCase());
       // console.log(data);
       if (data == this.hotspot.name) {
         // window.__krfn.utils.looktohotspot(this.$getKrpano(), this.hotspot.name);
         if (!this.showPanel) {
-          this.open(this.someData.hotspots[idx]);
+          this.open(this.hotspotList[idx]);
         }
         return;
       }
@@ -169,7 +201,8 @@ export default {
         }
       }
 
-      this.open(this.someData.hotspots[idx]);
+      // this.open(this.someData.hotspots[idx]);
+      this.open(this.hotspotList[idx]);
     });
   },
   methods: {
@@ -184,8 +217,8 @@ export default {
         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;
+          let idx = this.hotspotList.findIndex((item) => item.name == data.data.name);
+          this.hotspotList[idx] = data.data;
         } else {
           this.deleteKRHotspot(data.data);
         }
@@ -206,11 +239,11 @@ export default {
       let HV = window.__krfn.utils.getHotspotHV(this.$getKrpano(), data.name);
       data.ath = HV.ath;
       data.atv = HV.atv;
-      let idx = this.someData.hotspots.findIndex((item) => item.name === data.name);
+      let idx = this.hotspotList.findIndex((item) => item.name === data.name);
       if (idx <= -1) {
-        this.someData.hotspots.push(data);
+        this.hotspotList.push(data);
       } else {
-        this.someData.hotspots[idx] = data;
+        this.hotspotList[idx] = data;
       }
 
       this.currentScene.someData = this.someData;
@@ -230,27 +263,74 @@ export default {
       this.updateInfo();
     },
     deleteHot(data) {
-      this.someData.hotspots.splice(
-        this.someData.hotspots.findIndex((item) => item.name === data.name),
+      this.hotspotList.splice(
+        this.hotspotList.findIndex((item) => item.name === data.name),
         1
       );
       this.deleteKRHotspot(data);
       this.currentScene.someData = this.someData;
-      this.updateInfo();
+      // this.updateInfo();
       this.$msg.success(this.$i18n.t("hotspot.delete") + this.$i18n.t("hotspot.success"));
     },
     open(data) {
+      console.error(data);
       let hotspotData = null;
-
       if (data.isAdd) {
-        console.error(this.currentScene);
         this.editTitle = this.$i18n.t("hotspot.add");
+        let customIconInfo = {
+          // 热点图标类型为自定义图标时,图标的数据
+          img: "",
+        };
+        let serialFrameInfo = {
+          // 热点图标类型为序列帧时,序列帧的数据
+          img: "",
+          frameNumber: 0, // 总帧数
+          duration: 0, // 总播放时长(秒)
+        };
+        let personalizedTagInfo = {
+          // 热点图标类型为个性标签时,个性标签的数据
+          isShowLine: true,
+          lineDirection: "left-top",
+          fillColor: "rgba(0, 0, 0, 0.5)",
+          borderColor: "rgba(255, 255, 255, 0.8)",
+          textColor: "rgba(255, 255, 255, 1)",
+          textDirection: "left-right",
+          isTextWrap: false,
+          textNumPerLine: 10,
+        };
+
+        let scene = null;
+        let hyperlink = "";
+        let textarea = "";
+        let image = [];
+        let audio = "";
+        let video = "";
+        let imageTextInfo = {
+          // 热点类型为图文时,图文内容
+          imageList: [],
+          text: "",
+          isApplyToAll: true,
+          audio: {},
+        };
+        let phoneInfo = {
+          // 热点类型为电话时,对应数据
+          phone: "",
+        };
+        let pdfInfo = {
+          // 热点类型为pdf时,对应数据
+          name: "",
+          url: "",
+        };
+        let articleInfo = {
+          html: "",
+        };
         hotspotData = {
           hotspotType: data.hotspotType, // 热点类型,切换场景、图片、视频、音频、链接、文本等等
-          navigationId: this.currentScene.id,
+          navigationId: this.currentScene.sid ? this.currentScene.sid : this.currentScene.id,
           hotspotIconType: "system_icon", // 热点图标的类型,系统图标(system_icon)、自定义图片(custom_image)、序列帧(serial_frame)、个性标签(personalized_tag)
           img: this.$config.getStaticResource("/panoassets/images/hotspot/icon/") + `img_doticon_${String(data.idxInSystemIconList).padStart(2, "0")}.svg`, // 热点图标类型为系统图标时,图标在展时段使用的url
           icontype: "icon" + data.idxInSystemIconList, // 热点图标类型为系统图标时,图标的id
+          fodderId: [],
           customIconInfo: {
             // 热点图标类型为自定义图标时,图标的数据
             img: "",
@@ -275,19 +355,18 @@ export default {
           name: "_" + this.$randomWord(true, 8, 8),
           hotspotTitle: this.$i18n.t("hotspot.click_to_comfirm"),
           fontSize: 12,
-          type: "",
-          link: "",
-          titleDisplayMode: "always", // 'always' | 'never' | 'hover' 标题显示方式
+          // type: "",
+          // link: "",
+          titleDisplayMode: 1, // 'always' | 'never' | 'hover' 标题显示方式
           titlePosition: "top", // 'top' | 'bottom' | 'left' | 'right' | 'custom' 标题相对图标位置
           ath: "",
           atv: "",
           size: 1,
-          secne: null,
+          workId: this.baseInfo.workId,
+          scene: null,
           hyperlink: "",
           textarea: "",
           image: [], // 热点类型为图片时,图片列表
-          audio: "",
-          video: "",
           imageTextInfo: {
             // 热点类型为图文时,图文内容
             imageList: [],
@@ -310,6 +389,7 @@ export default {
         };
 
         this.$bus.emit("addhotspot", hotspotData);
+
         this.$getKrpano().set("layer[tooltip_" + hotspotData.name + "].visible", true);
         // debugger;
         setTimeout(() => {
@@ -318,6 +398,7 @@ export default {
 
         console.log("hotspotData", hotspotData);
       } else {
+        console.error(123123);
         hotspotData = browser.CloneObject(data);
         /**
          * v1.3新增
@@ -387,8 +468,12 @@ export default {
          * end of v1.3新增
          */
       }
-      this.$store.commit("SetHotspot", hotspotData);
-      this.showPanel = true;
+      this.$store.commit("hotspot/SetHotspot", hotspotData);
+      console.error(this.isConfirmingPosi);
+      setTimeout(() => {
+        this.showPanel = true;
+        console.error(this.isConfirmingPosi);
+      }, 100);
 
       if (!data.isAdd) {
         this.editTitle = this.$i18n.t("hotspot.edit");

+ 1 - 1
packages/qjkankan-editor/src/views/hotspot/hotspotIconType/custom_image.vue

@@ -51,7 +51,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      hotspot: 'hotspot',
+      hotspot: "hotspot/hotspot",
     }),
   },
   methods: {

+ 1 - 1
packages/qjkankan-editor/src/views/hotspot/hotspotIconType/personalized_tag.vue

@@ -278,7 +278,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      hotspot: "hotspot",
+       hotspot: "hotspot/hotspot",
     }),
     currentTextDirectionIdx() {
       switch (this.hotspot.personalizedTagInfo.textDirection) {

+ 1 - 1
packages/qjkankan-editor/src/views/hotspot/hotspotIconType/serial_frame.vue

@@ -103,7 +103,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      hotspot: "hotspot",
+       hotspot: "hotspot/hotspot",
     }),
   },
   watch: {

+ 1 - 1
packages/qjkankan-editor/src/views/hotspot/hotspotIconType/system_icon.vue

@@ -46,7 +46,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      hotspot: "hotspot",
+       hotspot: "hotspot/hotspot",
     }),
   },
   methods: {

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

@@ -144,7 +144,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      hotspot: "hotspot",
+       hotspot: "hotspot/hotspot",
     }),
   },
   methods: {

+ 1 - 1
packages/qjkankan-editor/src/views/hotspot/hotspotType/pdf.vue

@@ -36,7 +36,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      hotspot: "hotspot",
+       hotspot: "hotspot/hotspot",
       currentScene: "scene/currentScene",
     }),
   },

+ 1 - 1
packages/qjkankan-editor/src/views/hotspot/hotspotType/phone.vue

@@ -25,7 +25,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      hotspot: "hotspot",
+       hotspot: "hotspot/hotspot",
     }),
   },
 

+ 12 - 2
packages/qjkankan-editor/src/views/mask/setting.vue

@@ -105,10 +105,11 @@ export default {
     ...mapGetters({
       currentScene: "scene/currentScene",
       baseInfo: "base/baseInfo",
+      workCustomMaskList: "mask/workCustomMaskList",
     }),
 
     currentMask() {
-      return this.baseInfo.workCustomMaskList.find((item) => item.navigationId == this.currentScene.id);
+      return this.workCustomMaskList.find((item) => item.navigationId == this.currentScene.id || item.navigationId == this.currentScene.sid);
     },
   },
   data() {
@@ -139,6 +140,15 @@ export default {
     };
   },
   watch: {
+    baseInfo: {
+      handler(newVal, oldVal) {
+        if (newVal && this.$route.name == "mask") {
+          console.error("mask change");
+          this.$store.commit("scene/setSaveApiList", "mask");
+        }
+      },
+      deep: true,
+    },
     sky: {
       handler: function (val) {
         if (this.currentScene.type === "pano" && val) {
@@ -205,7 +215,7 @@ export default {
     currentScene: {
       handler: function (newVal, oldVal) {
         if (newVal && newVal !== oldVal) {
-          let item = this.baseInfo.workCustomMaskList.find((item) => item.navigationId == this.currentScene.id);
+          let item = this.workCustomMaskList.find((item) => item.navigationId == this.currentScene.id || item.navigationId == this.currentScene.sid);
 
           const { sky, earth } = item.data;
 

+ 8 - 3
packages/qjkankan-editor/src/views/navigation/groupSettings.vue

@@ -47,6 +47,7 @@ export default {
     ...mapGetters({
       // info: "info",
       info: "base/baseInfo",
+      isSave: "navigation/isSave",
       catalogTopology: "catalogTopology",
     }),
   },
@@ -57,9 +58,13 @@ export default {
     "info.navigationTrees": {
       // immediate: true,
       handler: function (newVal) {
-        if (newVal) {
-          console.error("navigationTrees change");
-          this.$store.commit("scene/setSaveApiList", "navigation");
+        if (newVal && this.$route.name == "navigation") {
+          if (!this.isSave) {
+            console.error("navigationTrees change", this.isSave);
+            this.$store.commit("scene/setSaveApiList", "navigation");
+          } else {
+            this.$store.commit("navigation/setData", { isSave: false });
+          }
         }
       },
       deep: true,

+ 1 - 1
packages/qjkankan-editor/src/views/navigation/initialSceneSettings.vue

@@ -49,7 +49,7 @@ export default {
     "info.firstScene": {
       immediate: true,
       handler: function (newVal, oldVal) {
-        if (JSON.stringify(newVal) != JSON.stringify(oldVal)) {
+        if (JSON.stringify(newVal) != JSON.stringify(oldVal) && JSON.stringify(oldVal) != "undefined") {
           console.error("firstScene change", JSON.stringify(newVal), "*****", JSON.stringify(oldVal));
           this.$store.commit("navigation/setData", { saveFristScene: true });
         }

+ 14 - 4
packages/qjkankan-editor/src/views/screen/Setting.vue

@@ -76,6 +76,7 @@ export default {
   computed: {
     ...mapGetters({
       currentScene: "scene/currentScene",
+      workVisualAngleList: "screen/workVisualAngleList",
       baseInfo: "base/baseInfo",
       sceneList: "base/sceneList",
     }),
@@ -93,6 +94,15 @@ export default {
     };
   },
   watch: {
+    baseInfo: {
+      handler(newVal, oldVal) {
+        if (newVal && this.$route.name == "screen") {
+          console.error("screen change");
+          this.$store.commit("scene/setSaveApiList", "screen");
+        }
+      },
+      deep: true,
+    },
     "$route.name": {
       handler() {
         this.handleHiddenAllMasks();
@@ -127,7 +137,7 @@ export default {
         if (val) {
           console.error("currentScene change", val);
           // let vlookatmin, vlookatmax;
-          let item = this.baseInfo.workVisualAngleList.find((item) => item.navigationId == this.currentScene.id);
+          let item = this.workVisualAngleList.find((item) => item.navigationId == this.currentScene.id || item.navigationId == this.currentScene.sid);
 
           if (item) {
             const { vlookatmin, vlookatmax } = item;
@@ -184,13 +194,13 @@ export default {
   },
   methods: {
     handleChange(value, index) {
-      this.baseInfo.workVisualAngleList.forEach((item, index) => {
-        if (item.navigationId == this.currentScene.id) {
+      this.workVisualAngleList.forEach((item, index) => {
+        if (item.navigationId == this.currentScene.id || item.navigationId == this.currentScene.sid) {
           item.vlookatmin = this.vlookat[0];
           item.vlookatmax = this.vlookat[1];
         }
       });
-
+      console.error(this.workVisualAngleList);
       // 拖动结束时的处理逻辑
     },
     onClickGo4dkk() {