jinx 11 月之前
父节点
当前提交
75ceb1bc63
共有 28 个文件被更改,包括 2384 次插入804 次删除
  1. 10 5
      packages/qjkankan-editor/src/Store/modules/hotspot.js
  2. 1 1
      packages/qjkankan-editor/src/Store/modules/mask.js
  3. 1 0
      packages/qjkankan-editor/src/Store/modules/scene.js
  4. 1 1
      packages/qjkankan-editor/src/components/dragTree/index.vue
  5. 21 23
      packages/qjkankan-editor/src/framework/EditorHead.vue
  6. 3 3
      packages/qjkankan-editor/src/framework/play/pano/components/new-list.vue
  7. 9 8
      packages/qjkankan-editor/src/views/hotspot/HotSpotList.vue
  8. 3 2
      packages/qjkankan-editor/src/views/mask/setting.vue
  9. 7 2
      packages/qjkankan-editor/src/views/screen/Setting.vue
  10. 2 2
      packages/qjkankan-view/.env.testdev
  11. 2 1
      packages/qjkankan-view/public/showviewer/lib/krpano/tooltip.xml
  12. 13 24
      packages/qjkankan-view/src/apis/index.js
  13. 89 56
      packages/qjkankan-view/src/components/Pano/index.vue
  14. 506 0
      packages/qjkankan-view/src/components/UIGather/list copy 2.vue
  15. 589 0
      packages/qjkankan-view/src/components/UIGather/list copy.vue
  16. 324 459
      packages/qjkankan-view/src/components/UIGather/list.vue
  17. 441 0
      packages/qjkankan-view/src/components/UIGather/new-list.vue
  18. 3 7
      packages/qjkankan-view/src/components/assembly/Password.vue
  19. 1 1
      packages/qjkankan-view/src/components/assembly/titieSlide.vue
  20. 11 13
      packages/qjkankan-view/src/hooks/useAudio.js
  21. 174 126
      packages/qjkankan-view/src/pages/show.vue
  22. 8 12
      packages/qjkankan-view/src/sdk/QJKanKan/index.js
  23. 5 5
      packages/qjkankan-view/src/sdk/QJKanKan/modules/Scene.js
  24. 25 32
      packages/qjkankan-view/src/sdk/QJKanKan/modules/Tags.js
  25. 5 4
      packages/qjkankan-view/src/sdk/QJKanKan/modules/hotspot.js
  26. 14 14
      packages/qjkankan-view/src/store/modules/scene.js
  27. 112 3
      packages/qjkankan-view/src/store/modules/tags.js
  28. 4 0
      packages/qjkankan-view/vue.config.js

+ 10 - 5
packages/qjkankan-editor/src/Store/modules/hotspot.js

@@ -221,16 +221,21 @@ export default {
   },
   actions: {
     save({ commit, state, rootState }, payload) {
-      console.error("saveHotspot", 1);
       let list = deepClone(state.hotspotList);
 
       list.forEach((item) => {
-        console.error("saveHotspot", 2);
         let current = rootState.base.sceneList.find((s_item) => s_item.sid && s_item.sid == item.navigationId);
-        console.error("saveHotspot", 3);
         if (current) {
           item.navigationId = current.id;
         }
+        if (item.hotspotType == "scene" && typeof item.scene.id != "number" && item.scene.id.indexOf("add") != -1) {
+          //场景类型 如果场景是新增,则scene的id也需要从服务端取值
+          let current = rootState.base.sceneList.find((s_item) => s_item.sid && s_item.sid == item.scene.sid);
+          if (current) {
+            console.error('')
+            item.scene.id = current.id;
+          }
+        }
         if (typeof item.id != "number" && item.id.indexOf("add") != -1) {
           delete item.id;
         }
@@ -248,7 +253,6 @@ export default {
           }
           delete item[value];
         }
-        console.error("saveHotspot", 4);
         let hotSpotIconType = item.hotspotIconType;
         for (let key in state.hotspotIconTypeList) {
           let value = state.hotspotIconTypeList[key];
@@ -261,7 +265,8 @@ export default {
         }
       });
       console.error(state.hotspotList, list);
-
+      // $waiting.hide();
+      // return;
       let data = { list, workId: rootState.base.baseInfo.workId };
 
       return new Promise((resolve, reject) => {

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

@@ -114,7 +114,7 @@ export default {
           list.push(item.data[key]);
         }
       });
-      console.error(list);
+      // console.error(list);
 
       // return
 

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

@@ -114,6 +114,7 @@ export default {
 
     // 设置当前场景列表
     setCurrentScenesList(state, payload) {
+      console.error(4);
       state.currentScenesList = payload;
     },
 

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

@@ -193,7 +193,7 @@ export default {
     "info.firstScene": {
       // immediate: true,
       handler: function (newVal, oldVal) {
-        if (!newVal) {
+        if (!newVal&&oldVal ) {
           console.error("设置空");
           this.$store.commit("scene/setCurrentScene", null);
         }

+ 21 - 23
packages/qjkankan-editor/src/framework/EditorHead.vue

@@ -93,9 +93,12 @@ export default {
       currentScene: "scene/currentScene",
       isEditing: "isEditing",
       saveApiList: "scene/saveApiList",
+      currentRootId: "navigation/currentRootId",
+      currentSecondId: "navigation/currentSecondId",
     }),
 
     info() {
+      console.error(this.currentSecondId);
       if (this.baseInfo) {
         this.$store.commit("base/ininDefaultData");
         //初始化
@@ -105,44 +108,39 @@ export default {
         } else {
           // firstScene = this.baseInfo.navigationTrees[0].children[0];
           firstScene = this.sceneList[0];
-
-          // this.$store.commit("scene/setCurrentScenesList", this.baseInfo.navigationTrees[0].children);
         }
 
         if (!this.currentScene) {
-          let activeScene = null;
-
-          this.baseInfo.navigationTrees.forEach((item, index) => {
-            activeScene = item.children.find((pano) => pano.id == firstScene.id);
+          this.$store.commit("scene/setCurrentScene", firstScene);
+        }
+        let activeScene = null;
+        this.baseInfo.navigationTrees.forEach((item, index) => {
+          activeScene = item.children.find((pano) => pano.id == firstScene.id);
+
+          if (activeScene) {
+            this.$store.commit("scene/setCurrentScenesList", item.children);
+            this.$store.commit("navigation/setData", { currentSecondId: null, currentRootId: item.id });
+            // throw new Error("LoopTerminated");
+          }
+          item = item.children.forEach((s_item, s_index) => {
+            activeScene = s_item.children.find((pano) => pano.id == firstScene.id);
 
             if (activeScene) {
-              this.$store.commit("scene/setCurrentScenesList", item.children);
-              this.$store.commit("navigation/setData", { currentSecondId: null, currentRootId: item.id });
+              this.$store.commit("scene/setCurrentScenesList", s_item.children);
+              this.$store.commit("navigation/setData", { currentSecondId: s_item.id, currentRootId: item.id });
               // throw new Error("LoopTerminated");
             }
-            item = item.children.forEach((s_item, s_index) => {
-              activeScene = s_item.children.find((pano) => pano.id == firstScene.id);
+            s_item = s_item.children.forEach((t_item, t_index) => {
+              activeScene = t_item.children.find((pano) => pano.id == firstScene.id);
 
               if (activeScene) {
                 this.$store.commit("scene/setCurrentScenesList", s_item.children);
                 this.$store.commit("navigation/setData", { currentSecondId: s_item.id, currentRootId: item.id });
                 // throw new Error("LoopTerminated");
               }
-              s_item = s_item.children.forEach((t_item, t_index) => {
-                activeScene = t_item.children.find((pano) => pano.id == firstScene.id);
-
-                if (activeScene) {
-                  this.$store.commit("scene/setCurrentScenesList", s_item.children);
-                  this.$store.commit("navigation/setData", { currentSecondId: s_item.id, currentRootId: item.id });
-                  // throw new Error("LoopTerminated");
-                }
-              });
             });
           });
-
-          this.$store.commit("scene/setCurrentScene", firstScene);
-        }
-
+        });
         // if (data.firstScene) {
         //   firstScene = data.scenes.find((item) => item.sceneCode == data.firstScene.sceneCode);
         // }

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

@@ -66,7 +66,7 @@
       </div>
     </div>
     <div class="bottom-com">
-      <div :style="`width:${catalogRootW}px;`" class="root-group-list swiper-container" ref="root-group">
+      <div v-if="info.navigationTrees.length > 1" :style="`width:${catalogRootW}px;`" class="root-group-list swiper-container" ref="root-group">
         <div class="swiper-wrapper root-group-wrapper">
           <div
             class="swiper-slide root-group-slide"
@@ -127,7 +127,7 @@ export default {
     currentScenesList(val) {
       this.$nextTick(() => {
         this.initSceneSwiper();
-        this.initRootGroupSwiper();
+        // this.initRootGroupSwiper();
         if (this.info.navigationTrees[this.currentRootId]?.children[this.currentSecondId]?.type == "group") {
           this.initSecondGroupSwiper();
         }
@@ -176,7 +176,7 @@ export default {
       return this.info.navigationTrees[this.rootTabIndex].children.findIndex((item) => item.id == this.currentSecondId);
     },
     showSecondTab() {
-      return this.info.navigationTrees[this.rootTabIndex].children.some((item) => item.id != this.currentSecondId );
+      return this.info.navigationTrees[this.rootTabIndex].children.some((item) => item.id != this.currentSecondId);
     },
   },
   methods: {

+ 9 - 8
packages/qjkankan-editor/src/views/hotspot/HotSpotList.vue

@@ -164,13 +164,14 @@ export default {
       // 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>=0) {
+
+      if (data.hpname.toLowerCase() == this.hotspot.name.toLowerCase()) {
+        //兼容新增
+        console.error("兼容新增");
+        this.hotspot.ath = data.ath;
+        this.hotspot.atv = data.atv;
+      }
+      if (hptarget >= 0) {
         this.hotspotList[hptarget].ath = data.ath;
         this.hotspotList[hptarget].atv = data.atv;
         // console.log("hptarget", this.hotspotList[hptarget]);
@@ -181,7 +182,7 @@ export default {
     this.$bus.on("openHotspot", (data) => {
       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());
+      // 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.hotspotList[idx].name) {

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

@@ -143,7 +143,7 @@ export default {
   watch: {
     currentMask: {
       handler(newVal, oldVal) {
-        if (newVal && this.$route.name == "mask") {
+        if (newVal && this.$route.name == "mask" && newVal.navigationId == oldVal.navigationId) {
           console.error("mask change");
           this.$store.commit("scene/setSaveApiList", "mask");
         }
@@ -155,7 +155,6 @@ export default {
         if (this.currentScene.type === "pano" && val) {
           // this.currentScene.customMask.sky = val;
           // this.updateCurrentScene();
-          console.error(val);
           this.handlePeakStatus(val.isShow);
           this.handlePeakScale(val.scale);
           this.handlePeakURL(val.icon);
@@ -186,6 +185,7 @@ export default {
               this.$store.commit("mask/applycustomMaskToAll", { type: "sky", currentMask: this.currentMask });
               this.$msg.success(this.$i18n.t("gather.edit_success"));
               setTimeout(() => (this.isApplySkyToAll = false), 1000);
+              this.$store.commit("scene/setSaveApiList", "mask");
             },
             no: () => {
               this.isApplySkyToAll = false;
@@ -204,6 +204,7 @@ export default {
               this.$store.commit("mask/applycustomMaskToAll", { type: "earth", currentMask: this.currentMask });
               this.$msg.success(this.$i18n.t("gather.edit_success"));
               setTimeout(() => (this.isApplyEarthToAll = false), 1000);
+              this.$store.commit("scene/setSaveApiList", "mask");
             },
             no: () => {
               this.isApplyEarthToAll = false;

+ 7 - 2
packages/qjkankan-editor/src/views/screen/Setting.vue

@@ -91,6 +91,7 @@ export default {
       initImg: "",
       vlookat: [-90, 90],
       applyToAll: false,
+      changeScene: false,
     };
   },
   watch: {
@@ -126,11 +127,12 @@ export default {
     currentScene: {
       handler(val) {
         if (val) {
-          console.error("currentScene change", val);
+          // console.error("currentScene change", val);
           // let vlookatmin, vlookatmax;
           let item = this.workVisualAngleList.find((item) => item.navigationId == this.currentScene.id || item.navigationId == this.currentScene.sid);
 
           if (item) {
+            this.changeScene = true;
             const { vlookatmin, vlookatmax } = item;
             if (vlookatmin && vlookatmax) {
               this.vlookat = [vlookatmin, vlookatmax];
@@ -152,11 +154,13 @@ export default {
     },
     vlookat: {
       handler: function (val) {
+        console.error(this.changeScene);
         this.handleVlootAt(val);
-        if (val && this.$route.name == "screen") {
+        if (val && this.$route.name == "screen" && this.changeScene == false) {
           console.error("screen change");
           this.$store.commit("scene/setSaveApiList", "screen");
         }
+        this.changeScene = false;
       },
     },
     applyToAll: {
@@ -177,6 +181,7 @@ export default {
               // this.updateCurrentScene();
               this.$msg.success(this.$i18n.t("gather.edit_success"));
               setTimeout(() => (this.applyToAll = false), 1000);
+              this.$store.commit("scene/setSaveApiList", "screen");
             },
             no: () => {
               this.applyToAll = false;

+ 2 - 2
packages/qjkankan-view/.env.testdev

@@ -2,9 +2,9 @@ VUE_APP_STATIC_DIR=showviewer
 VUE_APP_CDN=https://ossxiaoan.4dage.com
 VUE_APP_PROXY_URL_ROOT='https://test.4dkankan.com'
 VUE_APP_RESOURCE_URL='https://test.4dkankan.com/panorama/'
-VUE_APP_PROXY_URL='https://test.4dkankan.com/qjkankan/'
 VUE_APP_URL_FILL=
-
+# VUE_APP_PROXY_URL='https://test.4dkankan.com/qjkankan/'
+VUE_APP_PROXY_URL='http://192.168.0.41:8002/qjkankan/'
 # 接口请求地址
 VUE_APP_APIS_URL=https://test.4dkankan.com/
 VUE_APP_DEBBUG_FLAG=0516-03

+ 2 - 1
packages/qjkankan-view/public/showviewer/lib/krpano/tooltip.xml

@@ -197,6 +197,7 @@
             set_label_pos(get(tooltipname),get(pos));
          ); -->
           if(hoverstatus == 0,
+          trace('测试:',get(hoverstatus));
             delayedcall(0.5,
             txtadd(tooltipname, 'tooltip_', get(name)); 
             set_label_pos(get(tooltipname),get(pos));
@@ -207,7 +208,7 @@
          );
           <!-- 2 hover  -->
         if(hoverstatus == 2,
-            <!-- trace('测试'); -->
+            trace('测试');
            set(layer[get(tooltipname)].visible,false);
             delayedcall(0.5,
              txtadd(tooltipname, 'tooltip_', get(name)); 

+ 13 - 24
packages/qjkankan-view/src/apis/index.js

@@ -24,12 +24,7 @@ const URL_FILL = config.urlFill;
  * @param {*} no
  */
 export function getPanoInfo(ok, no) {
-  return http.get(
-    `${ossUrl}/720yun_fd_manage/${number()}/someData.json?_=${Math.random()}`,
-    {},
-    ok,
-    no
-  );
+  return http.get(`${ossUrl}/720yun_fd_manage/${number()}/someData.json?_=${Math.random()}`, {}, ok, no);
 }
 
 /**
@@ -39,12 +34,7 @@ export function getPanoInfo(ok, no) {
  * @param {*} no
  */
 export function getFdkkInfo(data, ok, no) {
-  return http.get(
-    `${fdkkURL}api/scene/getInfo?num=${data.num}&_=${Math.random()}`,
-    {},
-    ok,
-    no
-  );
+  return http.get(`${fdkkURL}api/scene/getInfo?num=${data.num}&_=${Math.random()}`, {}, ok, no);
 }
 
 /**
@@ -54,12 +44,7 @@ export function getFdkkInfo(data, ok, no) {
  * @param {*} no
  */
 export function checkWork(ok, no) {
-  return http.get(
-    `${URL_FILL}/web/common/checkWork/${number()}?visit=1111&val=0`,
-    {},
-    ok,
-    no
-  );
+  return http.get(`${URL_FILL}/web/common/checkWork/${number()}?visit=1111&val=0`, {}, ok, no);
 }
 
 /**
@@ -69,10 +54,14 @@ export function checkWork(ok, no) {
  * @param {*} no
  */
 export function exchangeId(data, ok, no) {
-  return http.post(
-    `${URL_FILL}/web/common/getIdInfo`,
-    data,
-    ok,
-    no
-  );
+  return http.post(`${URL_FILL}/web/common/getIdInfo`, data, ok, no);
+}
+/**
+ * 检查作品是否可用
+ * @param {*} data
+ * @param {*} ok
+ * @param {*} no
+ */
+export function getWorkInfo(ok, no) {
+  return http.get(`${URL_FILL}/work/view?workId=${number()}`, {}, ok, no);
 }

+ 89 - 56
packages/qjkankan-view/src/components/Pano/index.vue

@@ -4,15 +4,7 @@
 </template>
 
 <script setup>
-import {
-  ref,
-  onMounted,
-  computed,
-  watch,
-  nextTick,
-  unref,
-  watchEffect,
-} from "vue";
+import { ref, onMounted, computed, watch, nextTick, unref, watchEffect } from "vue";
 import { useStore } from "vuex";
 import { useApp, getApp } from "@/app";
 import Fdkk from "../Fdkk";
@@ -26,13 +18,12 @@ const store = useStore();
 const isMobile = computed(() => browser.isMobile());
 const lang = computed(() => config.lang);
 
+const hotspots = computed(() => store.getters["tags/hotspots"]);
 const currentScene = computed(() => store.getters["scene/currentScene"]);
 const isHasNormalBGM = computed(() => store.getters["audio/isHasNormalBGM"]);
 const scenesList = computed(() => store.getters["scene/list"]);
 const metadata = computed(() => store.getters["scene/metadata"]);
-const currentPlaying = computed(
-  () => store.getters["functions/currentPlaying"]
-);
+const currentPlaying = computed(() => store.getters["functions/currentPlaying"]);
 
 const hadGetInfo = ref(false);
 
@@ -40,28 +31,86 @@ const loadScene = async (currentScene) => {
   let app = await getApp();
   // await new Promise((r) => setTimeout(r, 10000));
   console.error("loadScene", unref(currentScene).id);
+  console.error(app.krpanoDom);
   if (app.krpanoDom) {
     let { sceneCode, initVisual, someData } = currentScene;
-    app.krpanoDom.call(
-      `skin_loadscene('scene_${sceneCode}',${
-        initVisual ? initVisual.vlookat : "0"
-      },${initVisual ? initVisual.hlookat : "0"})`
-    );
 
-    if (someData && someData.hotspots && someData.hotspots.length > 0) {
-      app.Tags.initHotspot(someData.hotspots, false);
+    let currnetVisual = metadata.value.workVisualAngleList.forEach((item) => {
+      item.navigationId == currentScene.id;
+    });
+    app.krpanoDom.call(`skin_loadscene('scene_${sceneCode}',${currnetVisual ? currnetVisual.vlookat : "0"},${currnetVisual ? currnetVisual.hlookat : "0"})`);
+
+    if (hotspots.value.length) {
+      let currentHotspots = hotspots.value.filter((item) => item.navigationId == currentScene.id);
+
+      if (currentHotspots.length) {
+        // hotspots.forEach((item, index) => {
+        //   if (item.content) {
+        //     let hotSpotType = item.hotspotType;
+        //     for (let key in hotspotTypeList.value) {
+        //       let data = hotspotTypeList.value[key];
+        //       if (key == hotSpotType && item.content[data]) {
+        //         item[data] = item.content[data];
+        //       } else if (data) {
+        //         item[data] = dataType.value[data];
+        //       }
+        //     }
+
+        //     let hotSpotIconType = item.hotspotIconType;
+        //     for (let key in hotspotIconTypeList.value) {
+        //       let data = hotspotIconTypeList.value[key];
+        //       if (key == hotSpotIconType && item.content[data]) {
+        //         item[data] = item.content[data];
+        //       } else if (data) {
+        //         item[data] = dataType.value[data];
+        //       }
+        //     }
+        //   }
+        // });
+        app.Tags.initHotspot(currentHotspots, false);
+      }
     }
 
-    const { vlookat, hlookat, vlookatmax, vlookatmin } =
-      currentScene.initVisual;
+    // const { vlookat, hlookat, vlookatmax, vlookatmin } =
+    //   currentScene.initVisual;
     app.krpanoDom.set(`view.limitview`, "lookat");
-    app.krpanoDom.set(`view.vlookat`, vlookat || 0);
-    app.krpanoDom.set(`view.hlookat`, hlookat || 0);
-    app.krpanoDom.set(`view.vlookatmin`, vlookatmin);
-    app.krpanoDom.set(`view.vlookatmax`, vlookatmax);
+    app.krpanoDom.set(`view.vlookat`, currnetVisual ? currnetVisual.vlookat : 0);
+    app.krpanoDom.set(`view.hlookat`, currnetVisual ? currnetVisual.hlookat : 0);
+    app.krpanoDom.set(`view.vlookatmin`, currnetVisual ? currnetVisual.vlookatmin : -90);
+    app.krpanoDom.set(`view.vlookatmax`, currnetVisual ? currnetVisual.vlookatmax : 90);
+
+    // console.log("customMasks", currentScene.customMask);
+    // const { earth, sky } = currentScene.customMask;
+    let customMask = metadata.value.workCustomMaskList.find((item) => item.navigationId == currentScene.id);
 
-    console.log("customMasks", currentScene.customMask);
-    const { earth, sky } = currentScene.customMask;
+    console.error(customMask);
+    if (!customMask) {
+      customMask = {
+        data: {
+          earth: {
+            antidistorted: true,
+            fodderId: null,
+            icon: "",
+            isShow: false,
+            navigationId: currentScene.id,
+            scale: 1,
+            type: "earth",
+          },
+          sky: {
+            antidistorted: true,
+            fodderId: null,
+            icon: "",
+            isShow: true,
+            navigationId: currentScene.id,
+            scale: 1,
+            type: "sky",
+          },
+        },
+        navigationId: currentScene.id,
+      };
+    }
+    // const { sky, earth } = currentScene.value.customMask;
+    const { sky, earth } = customMask.data;
     handleMasksUpdate(sky, earth, app);
   }
 };
@@ -76,9 +125,7 @@ watch(
       null,
       ""
         .concat(window.location.pathname, "?")
-        .concat(
-          `id=${metadata.value.id}&vr=${newVal.sceneCode}&lang=${lang.value}`
-        )
+        .concat(`id=${metadata.value.workId}&vr=${newVal.sceneCode}&lang=${lang.value}`)
         .concat(`${vlog ? "&vlog=" + vlog : ""} `)
     );
 
@@ -109,11 +156,7 @@ watch(
         store.commit("scene/setFdkkCurrentVersion", isVersion);
         // v3
         if (isVersion === "V3") {
-          let flag =
-            data.data.bgMusic &&
-            data.data.bgMusic != "0" &&
-            data.data.bgMusic != "Cheerful" &&
-            data.data.bgMusic != "noMusic";
+          let flag = data.data.bgMusic && data.data.bgMusic != "0" && data.data.bgMusic != "Cheerful" && data.data.bgMusic != "noMusic";
 
           console.error("是否有V3--BGM", flag);
           store.commit("fdkk/setV3FdkkBGM", flag);
@@ -137,9 +180,7 @@ watch(
 );
 
 const updateListPosi = () => {
-  let catalog = metadata.value.catalogs.find(
-    (item) => item.id == currentScene.value.category
-  );
+  let catalog = metadata.value.catalogs.find((item) => item.id == currentScene.value.category);
 
   // 查询初始场景的所在1级分组
   metadata.value.catalogRoot.forEach((item) => {
@@ -156,25 +197,27 @@ const updateListPosi = () => {
 
 useApp().then((app) => {
   app.Tags.on("clickHotspot", (data) => {
+    console.error("clickHotspot", data);
     let { id } = data;
-    let hotspot = unref(currentScene).someData.hotspots.find(
-      (item) => item.name.toLowerCase() === id.toLowerCase()
-    );
-
+    // let hotspot = unref(currentScene).someData.hotspots.find((item) => item.name.toLowerCase() === id.toLowerCase());
+    let hotspot = hotspots.value.find((item) => item.name.toLowerCase() === id.toLowerCase());
+    console.error("clickHotspot", hotspot);
     if (hotspot) {
       const isNotclickType = ["tag"];
       if (!isNotclickType.includes(hotspot.hotspotType)) {
         console.log("click", hotspot);
         // store.commit("functions/setPauseFrom", "");
         // store.dispatch("audio/pauseBGM");
+        console.error(scenesList.value, hotspot.scene.id);
         if (hotspot.hotspotType == "phone" && unref(isMobile)) {
           window.open(`tel:${hotspot.phoneInfo.phone}`, "_self");
           return;
         }
         if (hotspot.hotspotType == "scene") {
+          console.error(scenesList.value.find((item) => item.id == hotspot.scene.id));
           store.commit(
             "scene/setCurrentScene",
-            scenesList.value.find((item) => item.id == hotspot.secne.id)
+            scenesList.value.find((item) => item.id == hotspot.scene.id)
           );
           updateListPosi();
         } else if (hotspot.hotspotType == "link") {
@@ -185,11 +228,7 @@ useApp().then((app) => {
           }
         } else {
           store.commit("tags/setCurrentTag", hotspot);
-          if (
-            hotspot.hotspotType == "audio" ||
-            hotspot.hotspotType == "imageText" ||
-            hotspot.hotspotType == "video"
-          ) {
+          if (hotspot.hotspotType == "audio" || hotspot.hotspotType == "imageText" || hotspot.hotspotType == "video") {
             store.dispatch("audio/pauseBGM");
             // store.commit("functions/setPauseFrom", currentPlaying.value);
           }
@@ -232,10 +271,7 @@ const handleMasksUpdate = (skyMask, earthMask, app) => {
   }
   if (earthMask) {
     if ("isShow" in earthMask) {
-      app.krpanoDom.set(
-        `hotspot[nadirlogo].visible`,
-        Boolean(earthMask.isShow)
-      );
+      app.krpanoDom.set(`hotspot[nadirlogo].visible`, Boolean(earthMask.isShow));
     }
     if (earthMask.icon) {
       app.krpanoDom.set(`hotspot[nadirlogo].url`, earthMask.icon);
@@ -244,10 +280,7 @@ const handleMasksUpdate = (skyMask, earthMask, app) => {
       app.krpanoDom.set(`hotspot[nadirlogo].scale`, earthMask.scale);
     }
     if ("antidistorted" in earthMask) {
-      app.krpanoDom.set(
-        `hotspot[nadirlogo].distorted`,
-        earthMask.antidistorted
-      );
+      app.krpanoDom.set(`hotspot[nadirlogo].distorted`, earthMask.antidistorted);
       if (!earthMask.antidistorted) {
         app.krpanoDom.set(`hotspot[nadirlogo].scale`, earthMask.scale * 0.9);
       }

+ 506 - 0
packages/qjkankan-view/src/components/UIGather/list copy 2.vue

@@ -0,0 +1,506 @@
+<template>
+  <div
+    class="bar-list"
+    v-if="show && !(metadata.navigationTrees && metadata.navigationTrees.length == 1 && scenes.length == 1 && metadata.navigationTrees[rootTabIndex].length == 1)"
+    :class="{ barshow: isShowScenesList }"
+  >
+    <div class="top-con">
+      <div class="swiper-container swiper1" :style="`width:calc(100% - 20px)`" id="swScenes" v-if="currentScenesList.length > 0">
+        <ul class="swiper-wrapper">
+          <li
+            @click="tabCurrentScene(item)"
+            class="swiper-slide"
+            :class="{
+              active: currentScene.sceneCode == item.sceneCode,
+              // loopspan:
+              //   item.name.length > spanlength &&
+              //   currentScene.id == item.id,
+            }"
+            :style="{ backgroundImage: `url(${item.icon})` }"
+            v-for="(item, i) in currentScenesList"
+            :key="i"
+          >
+            <i class="iconfont" :class="item.type == '4dkk' ? 'icon-editor_3d' : 'icon-editor_panoramic'"></i>
+            <div class="marquee">
+              <marquee-text :repeat="1" :duration="Math.ceil(item.name.length / 10) * 5" :key="item.id" v-if="item.name.length > spanlength && currentScene.id == item.id">
+                {{ item.name }}
+              </marquee-text>
+              <span v-else>
+                {{ item.name }}
+              </span>
+            </div>
+          </li>
+        </ul>
+      </div>
+      <div class="swiper-container swiper2" id="swSecondary" :style="`width:${clamp(secondaryW, 0, 1150)}px`" v-if="metadata.navigationTrees[rootTabIndex]?.children.length > 1">
+        <!-- {{ clamp(secondaryW, 0, 1150) }} -->
+        <ul class="swiper-wrapper">
+          <li
+            class="swiper-slide"
+            @click="tabSecondary(item, i)"
+            :class="{
+              active: currentSecondary.id == item.id,
+              // loopspan:
+              //   fixTitle(item.name).length > spanlength &&
+              //   currentSecondary.id == item.id,
+            }"
+            v-for="(item, i) in metadata.navigationTrees[rootTabIndex]?.children"
+            :key="i"
+          >
+            <!-- {{ Math.ceil(fixTitle(item.name).length / 10) }} -->
+
+            <marquee-text :duration="Math.ceil(fixTitle(item.name).length / 10) * 5" :key="item.id" :repeat="1" v-if="fixTitle(item.name).length > spanlength && currentSecondary.id == item.id">
+              {{ fixTitle(item.name) }}
+            </marquee-text>
+            <span v-else>
+              {{ fixTitle(item.name) }}
+            </span>
+            <!-- <span v-if="currentSecondary.id == item.id">{{
+              fixTitle(item.name)
+            }}</span>
+            <span v-else>{{
+              fixTitle(item.name).length > spanlength
+                ? fixTitle(item.name).slice(0, spanlength)
+                : fixTitle(item.name)
+            }}</span> -->
+          </li>
+        </ul>
+      </div>
+    </div>
+
+    <div class="swiper-container" id="swcatalogRoot" :style="`width:${catalogRootW > innerW ? '100%' : catalogRootW + 'px'}`" v-if="metadata.navigationTrees.length">
+      <ul class="swiper-wrapper" v-if="metadata.navigationTrees.length > 1">
+        <li
+          class="swiper-slide"
+          :class="{
+            active: currentCatalogRoot.id == item.id,
+            // loopspan:
+            //   fixTitle(item.name).length > spanlength &&
+            //   currentCatalogRoot.id == item.id,
+          }"
+          @click="tabRoot(item)"
+          v-for="(item, i) in metadata.navigationTrees"
+          :key="i"
+        >
+          <!-- <span v-if="currentCatalogRoot.id == item.id">{{
+            fixTitle(item.name)
+          }}</span>
+          <span v-else>{{
+            fixTitle(item.name).length > spanlength
+              ? fixTitle(item.name).slice(0, spanlength)
+              : fixTitle(item.name)
+          }}</span> -->
+
+          <marquee-text :duration="Math.ceil(fixTitle(item.name).length / 10) * 5" :key="item.id" :repeat="1" v-if="fixTitle(item.name).length > spanlength && currentCatalogRoot.id == item.id">
+            {{ fixTitle(item.name) }}
+          </marquee-text>
+          <span v-else>
+            {{ fixTitle(item.name) }}
+          </span>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, watch, computed, onMounted, nextTick, unref, watchEffect } from "vue";
+import { useStore } from "vuex";
+import { useApp } from "@/app";
+import MarqueeText from "vue-marquee-text-component";
+import { useI18n, getLocale } from "@/i18n";
+const { t } = useI18n({ useScope: "global" });
+
+const store = useStore();
+
+const spanlength = ref(5);
+
+const metadata = computed(() => store.getters["scene/metadata"]);
+const scenes = computed(() => store.getters["scene/list"]);
+const currentScene = computed(() => store.getters["scene/currentScene"]);
+const currentSecondId = computed(() => store.getters["scene/currentSecondId"]);
+const currentRootId = computed(() => store.getters["scene/currentRootId"]);
+
+const clamp = computed(() => (num, min, max) => Math.min(Math.max(num, min), max));
+
+const currentCatalogRoot = computed(() => store.getters["scene/currentCatalogRoot"]);
+const currentSecondary = computed(() => store.getters["scene/currentSecondary"]);
+
+const secondaryList = computed(() => store.getters["scene/secondaryList"]);
+
+const isShowScenesList = computed(() => store.getters["functions/isShowScenesList"]);
+
+const currentScenesList = computed(() => store.getters["scene/currentScenesList"]);
+
+const show = ref(false);
+
+const swidth = ref({
+  swcatalogRoot: 104,
+  swSecondary: 84,
+  swScenes: 72,
+});
+const rootTabIndex = computed(() => {
+  console.error(currentRootId.value);
+  return metadata.value && metadata.value?.navigationTrees ? metadata.value?.navigationTrees.findIndex((item) => item.id == currentRootId.value) : 0;
+});
+
+const secondTabIndex = computed(() => {
+  return metadata.value && metadata.value?.navigationTrees ? metadata.value.navigationTrees[rootTabIndex.value]?.children.findIndex((item) => item.id == currentSecondId.value) : 0;
+});
+const scenesListW = computed(() => currentScenesList.value.length * (swidth.value["swScenes"] + 10) - 10);
+const secondaryW = computed(() => metadata.value.navigationTrees[secondTabIndex.value].length * (swidth.value["swSecondary"] + 10) - 10);
+const catalogRootW = computed(() => metadata.value.navigationTrees.length * (swidth.value["swcatalogRoot"] + 10) - 10);
+
+const innerW = computed(() => 1150);
+
+const tabCurrentScene = (data) => {
+  console.log("tabCurrentScene", data.id, currentScene.value.id);
+  if (data.id !== currentScene.value.id) {
+    store.commit("scene/setCurrentScene", data);
+    setTimeout(() => {
+      scenesSwiperFocus();
+    }, 300);
+  } else {
+    console.log("重复点击当前导航");
+    // window.alert("alert-test-->重复点击当前导航");
+  }
+};
+
+const tabSecondary = (data, index) => {
+  store.commit("scene/setCurrentSecondary", data);
+};
+
+const tabRoot = (data) => {
+  store.commit("scene/setCurrentCatalogRoot", data);
+};
+
+const fixTitle = (name) => {
+  if (name == "默认二级分组") {
+    name = t("navigation.default_group_two");
+  } else if (name == "一级分组") {
+    name = t("navigation.group_one");
+  } else {
+    name = name;
+  }
+  return name;
+};
+const swiperOptions = {
+  slidesPerView: "auto",
+  centeredSlides: true,
+  spaceBetween: 10,
+  centerInsufficientSlides: true,
+  centeredSlidesBounds: true,
+  freeMode: {
+    enabled: true,
+    sticky: false,
+    momentumBounce: false,
+    // momentumVelocityRatio: 0.5,
+  },
+};
+
+// const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
+
+const initMainSwiper = () => {
+  nextTick(() => {
+    if (window.mainNatSwiper) {
+      // window.mainNatSwiper = null;
+      window.mainNatSwiper.update();
+      window.sencordNatSwiper.slideReset();
+    }
+    window.mainNatSwiper = new Swiper("#swcatalogRoot", swiperOptions);
+  });
+};
+const initsencordNatSwiper = () => {
+  nextTick(() => {
+    console.warn("initsencordNatSwiper");
+    if (window.sencordNatSwiper) {
+      window.sencordNatSwiper.update();
+      window.sencordNatSwiper.slideReset();
+    }
+    window.sencordNatSwiper = new Swiper("#swSecondary", swiperOptions);
+  });
+};
+const initScenesSwiper = () => {
+  // console.warn("initScenesSwiper");
+  nextTick(() => {
+    if (window.scenesNatSwiper) {
+      try {
+        window.scenesNatSwiper.slides.length > 0 && window.scenesNatSwiper.update();
+        window.scenesNatSwiper.slideReset();
+      } catch (error) {}
+
+      // window.scenesNatSwiper = null;
+    } else {
+      window.scenesNatSwiper = new Swiper("#swScenes", {
+        ...swiperOptions,
+      });
+    }
+    scenesSwiperFocus();
+  });
+};
+
+const scenesSwiperFocus = () => {
+  const sceneIndex = Array.from(currentScenesList.value).findIndex((item) => item.id === currentScene.value.id);
+  if (window.scenesNatSwiper && window.scenesNatSwiper.slides.length > 0) {
+    const index = sceneIndex < 0 ? 0 : sceneIndex;
+    const fIndex = index < 5 ? 0 : index;
+    console.warn("scenesSwiperFocus", fIndex);
+    window.scenesNatSwiper.slideTo(fIndex);
+  }
+};
+
+const sencordNatSwiperFocus = () => {
+  nextTick(() => {
+    const current = Array.from(secondaryList.value).findIndex((item) => item.id === currentSecondary.value.id);
+    if (window.sencordNatSwiper) {
+      const index = current < 0 ? 0 : current;
+      console.error("sencordNatSwiperFocus", index);
+      // window.sencordNatSwiper.slideTo(current);
+      window.sencordNatSwiper.slideTo(current);
+    }
+  });
+};
+
+onMounted(() => {
+  useApp().then(async (app) => {
+    show.value = true;
+    console.error("app", show.value);
+  });
+  watchEffect(() => {
+    if (metadata.value.navigationTrees && unref(metadata.value.navigationTrees).length > 0) {
+      initMainSwiper();
+    }
+  });
+
+  watch(secondTabIndex.value, () => {
+    if (unref(metadata.value.navigationTrees[rootTabIndex.value].children).length > 1) {
+      initsencordNatSwiper();
+      sencordNatSwiperFocus();
+    } else {
+      if (window.sencordNatSwiper) {
+        console.warn("destroy-sencordNatSwiper");
+        window.sencordNatSwiper.update();
+        window.sencordNatSwiper.slideReset();
+      }
+    }
+  });
+
+  watch(currentScenesList, () => {
+    initScenesSwiper();
+  });
+  watch(currentCatalogRoot, (val) => {
+    if (Array.from(unref(val).children).includes(currentScene.value.category)) {
+      //当前场景在一类的children
+      const activeSecond = Array.from(unref(secondaryList)).find((i) => i.id === currentScene.value.category);
+      // console.log("activeSecond", activeSecond);
+      store.commit("scene/setCurrentSecondary", activeSecond);
+      if (window.sencordNatSwiper) {
+        window.sencordNatSwiper.update();
+      }
+    }
+  });
+});
+</script>
+
+<style lang="scss" scoped>
+$width: 1150px;
+
+.bar-list {
+  position: absolute;
+  bottom: 68px;
+  left: 50%;
+  transform: translateX(-50%);
+  text-align: center;
+  max-width: $width;
+  overflow: hidden;
+  max-height: 0;
+  transition: 0.3s all ease;
+  z-index: 9;
+
+  .swiper-container {
+    width: 100%;
+    position: relative;
+    margin: 0 auto;
+
+    > ul {
+      > li {
+        white-space: nowrap;
+
+        > span,
+        > div > span {
+          cursor: pointer;
+          display: inline-block;
+          color: rgba(255, 255, 255, 0.6);
+        }
+
+        &.loopspan {
+          > span,
+          > div > span {
+            animation: 10s wordsLoop linear infinite normal;
+          }
+        }
+
+        &.active {
+          > span,
+          > div > span {
+            color: rgba(255, 255, 255, 1);
+          }
+        }
+      }
+    }
+  }
+
+  .top-con {
+    margin: 0 auto 10px;
+    padding: 10px 0;
+    background: linear-gradient(268deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.4) 25%, rgba(0, 0, 0, 0.4) 75%, rgba(0, 0, 0, 0) 100%);
+  }
+
+  #swcatalogRoot {
+    > ul {
+      > li {
+        width: 104px;
+        background: rgba(0, 0, 0, 0.5);
+        border-radius: 4px;
+        padding: 4px 10px;
+        border: 1px solid rgba(255, 255, 255, 0.5);
+        box-sizing: border-box;
+        overflow: hidden;
+
+        > span {
+          width: 100%;
+          word-break: keep-all;
+        }
+
+        &.active {
+          border: 1px solid rgba(255, 255, 255, 1);
+        }
+      }
+    }
+  }
+
+  #swSecondary {
+    margin: 20px auto 10px;
+
+    > ul {
+      > li {
+        width: 84px;
+        box-sizing: border-box;
+        overflow: hidden;
+        padding-bottom: 6px;
+
+        > span {
+          width: 100%;
+          word-break: keep-all;
+        }
+
+        &.active {
+          position: relative;
+
+          &::before {
+            content: "";
+            display: inline-block;
+            position: absolute;
+            bottom: 0;
+            width: 20px;
+            height: 2px;
+            z-index: 9999;
+            left: 50%;
+            transform: translateX(-50%);
+            background: var(--colors-primary-base);
+          }
+        }
+      }
+    }
+  }
+
+  #swScenes {
+    > ul {
+      > li {
+        cursor: pointer;
+        width: 72px;
+        height: 72px;
+        border-radius: 6px;
+        border: 1px solid #ffffff;
+        background-size: cover;
+        position: relative;
+        overflow: hidden;
+
+        .iconfont {
+          position: absolute;
+          left: 4px;
+          top: 4px;
+          z-index: 99;
+
+          &::after {
+            background: rgba(0, 0, 0, 0.3);
+            content: "";
+            width: 14px;
+            height: 14px;
+            display: inline-block;
+            position: absolute;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            z-index: -1;
+            filter: blur(4px);
+          }
+        }
+
+        > div {
+          position: absolute;
+          bottom: 0;
+          left: 0;
+          height: 20px;
+          background: rgba(0, 0, 0, 0.5);
+          width: 100%;
+          overflow: hidden;
+
+          > span,
+          div {
+            // width: 100%;
+            line-height: 20px;
+            word-break: keep-all;
+            white-space: normal;
+          }
+        }
+
+        &.active {
+          border: 1px solid var(--colors-primary-base);
+
+          > div {
+            > span {
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.barshow {
+  max-height: 190px;
+}
+
+@keyframes wordsLoop {
+  0% {
+    transform: translateX(100%);
+    -webkit-transform: translateX(100%);
+  }
+  100% {
+    transform: translateX(-180%);
+    -webkit-transform: translateX(-180%);
+  }
+}
+.marquee {
+  .marquee-text-wrap {
+    height: 20px;
+    line-height: 20px;
+  }
+}
+</style>
+<style>
+.marquee-text-text {
+  padding: 0 5px;
+}
+</style>

+ 589 - 0
packages/qjkankan-view/src/components/UIGather/list copy.vue

@@ -0,0 +1,589 @@
+<template>
+  <div
+    class="bar-list"
+    v-if="
+      show &&
+      !(
+        metadata.catalogRoot &&
+        metadata.catalogRoot.length == 1 &&
+        scenes.length == 1 &&
+        secondaryList.length == 1
+      )
+    "
+    :class="{ barshow: isShowScenesList }"
+  >
+    <div class="top-con">
+      <div
+        class="swiper-container swiper1"
+        :style="`width:calc(100% - 20px)`"
+        id="swScenes"
+        v-if="currentScenesList.length > 0"
+      >
+        <ul class="swiper-wrapper">
+          <li
+            @click="tabCurrentScene(item)"
+            class="swiper-slide"
+            :class="{
+              active: currentScene.sceneCode == item.sceneCode,
+              // loopspan:
+              //   item.sceneTitle.length > spanlength &&
+              //   currentScene.id == item.id,
+            }"
+            :style="{ backgroundImage: `url(${item.icon})` }"
+            v-for="(item, i) in currentScenesList"
+            :key="i"
+          >
+            <i
+              class="iconfont"
+              :class="
+                item.type == '4dkk' ? 'icon-editor_3d' : 'icon-editor_panoramic'
+              "
+            ></i>
+            <div class="marquee">
+              <marquee-text
+                :repeat="1"
+                :duration="Math.ceil(item.sceneTitle.length / 10) * 5"
+                :key="item.id"
+                v-if="
+                  item.sceneTitle.length > spanlength &&
+                  currentScene.id == item.id
+                "
+              >
+                {{ item.sceneTitle }}
+              </marquee-text>
+              <span v-else>
+                {{ item.sceneTitle }}
+              </span>
+            </div>
+          </li>
+        </ul>
+      </div>
+
+      <div
+        class="swiper-container swiper2"
+        id="swSecondary"
+        :style="`width:${clamp(secondaryW, 0, 1150)}px`"
+        v-if="secondaryList.length > 1"
+      >
+        <!-- {{ clamp(secondaryW, 0, 1150) }} -->
+        <ul class="swiper-wrapper">
+          <li
+            class="swiper-slide"
+            @click="tabSecondary(item, i)"
+            :class="{
+              active: currentSecondary.id == item.id,
+              // loopspan:
+              //   fixTitle(item.name).length > spanlength &&
+              //   currentSecondary.id == item.id,
+            }"
+            v-for="(item, i) in secondaryList"
+            :key="i"
+          >
+            <!-- {{ Math.ceil(fixTitle(item.name).length / 10) }} -->
+
+            <marquee-text
+              :duration="Math.ceil(fixTitle(item.name).length / 10) * 5"
+              :key="item.id"
+              :repeat="1"
+              v-if="
+                fixTitle(item.name).length > spanlength &&
+                currentSecondary.id == item.id
+              "
+            >
+              {{ fixTitle(item.name) }}
+            </marquee-text>
+            <span v-else>
+              {{ fixTitle(item.name) }}
+            </span>
+            <!-- <span v-if="currentSecondary.id == item.id">{{
+              fixTitle(item.name)
+            }}</span>
+            <span v-else>{{
+              fixTitle(item.name).length > spanlength
+                ? fixTitle(item.name).slice(0, spanlength)
+                : fixTitle(item.name)
+            }}</span> -->
+          </li>
+        </ul>
+      </div>
+    </div>
+
+    <div
+      class="swiper-container"
+      id="swcatalogRoot"
+      :style="`width:${catalogRootW > innerW ? '100%' : catalogRootW + 'px'}`"
+      v-if="metadata.catalogRoot.length > 0 && metadata.catalogs.length > 1"
+    >
+      <ul class="swiper-wrapper" v-if="metadata.catalogRoot.length > 1">
+        <li
+          class="swiper-slide"
+          :class="{
+            active: currentCatalogRoot.id == item.id,
+            // loopspan:
+            //   fixTitle(item.name).length > spanlength &&
+            //   currentCatalogRoot.id == item.id,
+          }"
+          @click="tabRoot(item)"
+          v-for="(item, i) in metadata.catalogRoot"
+          :key="i"
+        >
+          <!-- <span v-if="currentCatalogRoot.id == item.id">{{
+            fixTitle(item.name)
+          }}</span>
+          <span v-else>{{
+            fixTitle(item.name).length > spanlength
+              ? fixTitle(item.name).slice(0, spanlength)
+              : fixTitle(item.name)
+          }}</span> -->
+
+          <marquee-text
+            :duration="Math.ceil(fixTitle(item.name).length / 10) * 5"
+            :key="item.id"
+            :repeat="1"
+            v-if="
+              fixTitle(item.name).length > spanlength &&
+              currentCatalogRoot.id == item.id
+            "
+          >
+            {{ fixTitle(item.name) }}
+          </marquee-text>
+          <span v-else>
+            {{ fixTitle(item.name) }}
+          </span>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import {
+  ref,
+  watch,
+  computed,
+  onMounted,
+  nextTick,
+  unref,
+  watchEffect,
+} from "vue";
+import { useStore } from "vuex";
+import { useApp } from "@/app";
+import MarqueeText from "vue-marquee-text-component";
+import { useI18n, getLocale } from "@/i18n";
+const { t } = useI18n({ useScope: "global" });
+
+const store = useStore();
+
+const spanlength = ref(5);
+
+const metadata = computed(() => store.getters["scene/metadata"]);
+const scenes = computed(() => store.getters["scene/list"]);
+const currentScene = computed(() => store.getters["scene/currentScene"]);
+
+const clamp = computed(
+  () => (num, min, max) => Math.min(Math.max(num, min), max)
+);
+
+const currentCatalogRoot = computed(
+  () => store.getters["scene/currentCatalogRoot"]
+);
+const currentSecondary = computed(
+  () => store.getters["scene/currentSecondary"]
+);
+
+const secondaryList = computed(() => store.getters["scene/secondaryList"]);
+
+const isShowScenesList = computed(
+  () => store.getters["functions/isShowScenesList"]
+);
+
+const currentScenesList = computed(
+  () => store.getters["scene/currentScenesList"]
+);
+
+const show = ref(false);
+
+const swidth = ref({
+  swcatalogRoot: 104,
+  swSecondary: 84,
+  swScenes: 72,
+});
+
+const scenesListW = computed(
+  () => currentScenesList.value.length * (swidth.value["swScenes"] + 10) - 10
+);
+const secondaryW = computed(
+  () => secondaryList.value.length * (swidth.value["swSecondary"] + 10) - 10
+);
+const catalogRootW = computed(
+  () =>
+    metadata.value.catalogRoot.length * (swidth.value["swcatalogRoot"] + 10) -
+    10
+);
+const innerW = computed(() => 1150);
+
+const tabCurrentScene = (data) => {
+  console.log("tabCurrentScene", data.id, currentScene.value.id);
+  if (data.id !== currentScene.value.id) {
+    store.commit("scene/setCurrentScene", data);
+    setTimeout(() => {
+      scenesSwiperFocus();
+    }, 300);
+  } else {
+    console.log("重复点击当前导航");
+    // window.alert("alert-test-->重复点击当前导航");
+  }
+};
+
+const tabSecondary = (data, index) => {
+  store.commit("scene/setCurrentSecondary", data);
+};
+
+const tabRoot = (data) => {
+  store.commit("scene/setCurrentCatalogRoot", data);
+};
+
+const fixTitle = (name) => {
+  if (name == "默认二级分组") {
+    name = t("navigation.default_group_two");
+  } else if (name == "一级分组") {
+    name = t("navigation.group_one");
+  } else {
+    name = name;
+  }
+  return name;
+};
+const swiperOptions = {
+  slidesPerView: "auto",
+  centeredSlides: true,
+  spaceBetween: 10,
+  centerInsufficientSlides: true,
+  centeredSlidesBounds: true,
+  freeMode: {
+    enabled: true,
+    sticky: false,
+    momentumBounce: false,
+    // momentumVelocityRatio: 0.5,
+  },
+};
+
+// const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
+
+const initMainSwiper = () => {
+  nextTick(() => {
+    if (window.mainNatSwiper) {
+      // window.mainNatSwiper = null;
+      window.mainNatSwiper.update();
+      window.sencordNatSwiper.slideReset();
+    }
+    window.mainNatSwiper = new Swiper("#swcatalogRoot", swiperOptions);
+  });
+};
+const initsencordNatSwiper = () => {
+  nextTick(() => {
+    console.warn("initsencordNatSwiper");
+    if (window.sencordNatSwiper) {
+      window.sencordNatSwiper.update();
+      window.sencordNatSwiper.slideReset();
+    }
+    window.sencordNatSwiper = new Swiper("#swSecondary", swiperOptions);
+  });
+};
+const initScenesSwiper = () => {
+  // console.warn("initScenesSwiper");
+  nextTick(() => {
+    if (window.scenesNatSwiper) {
+      try {
+        window.scenesNatSwiper.slides.length > 0 &&  window.scenesNatSwiper.update();
+        window.scenesNatSwiper.slideReset();
+      } catch (error) {}
+
+      // window.scenesNatSwiper = null;
+    } else {
+      window.scenesNatSwiper = new Swiper("#swScenes", {
+        ...swiperOptions,
+      });
+    }
+    scenesSwiperFocus();
+  });
+};
+
+const scenesSwiperFocus = () => {
+  const sceneIndex = Array.from(currentScenesList.value).findIndex(
+    (item) => item.id === currentScene.value.id
+  );
+  if (window.scenesNatSwiper && window.scenesNatSwiper.slides.length > 0) {
+    const index = sceneIndex < 0 ? 0 : sceneIndex;
+    const fIndex = index < 5 ? 0 : index;
+    console.warn("scenesSwiperFocus", fIndex);
+    window.scenesNatSwiper.slideTo(fIndex);
+  }
+};
+
+const sencordNatSwiperFocus = () => {
+  nextTick(() => {
+    const current = Array.from(secondaryList.value).findIndex(
+      (item) => item.id === currentSecondary.value.id
+    );
+    if (window.sencordNatSwiper) {
+      const index = current < 0 ? 0 : current;
+      console.warn("sencordNatSwiperFocus", index);
+      // window.sencordNatSwiper.slideTo(current);
+      window.sencordNatSwiper.slideTo(current);
+    }
+  });
+};
+
+onMounted(() => {
+  useApp().then(async (app) => {
+    show.value = true;
+  });
+  watchEffect(() => {
+    if (
+      metadata.value.catalogRoot &&
+      unref(metadata.value.catalogRoot).length > 0
+    ) {
+      initMainSwiper();
+    }
+  });
+
+  watch([currentSecondary, secondaryList], () => {
+    if (unref(secondaryList).length > 1) {
+      initsencordNatSwiper();
+      sencordNatSwiperFocus();
+    } else {
+      if (window.sencordNatSwiper) {
+        console.warn("destroy-sencordNatSwiper");
+        window.sencordNatSwiper.update();
+        window.sencordNatSwiper.slideReset();
+      }
+    }
+  });
+
+  watch(currentScenesList, () => {
+    initScenesSwiper();
+  });
+  watch(currentCatalogRoot, (val) => {
+    if (Array.from(unref(val).children).includes(currentScene.value.category)) {
+      //当前场景在一类的children
+      const activeSecond = Array.from(unref(secondaryList)).find(
+        (i) => i.id === currentScene.value.category
+      );
+      // console.log("activeSecond", activeSecond);
+      store.commit("scene/setCurrentSecondary", activeSecond);
+      if (window.sencordNatSwiper) {
+        window.sencordNatSwiper.update();
+      }
+    }
+  });
+});
+</script>
+
+<style lang="scss" scoped>
+$width: 1150px;
+
+.bar-list {
+  position: absolute;
+  bottom: 68px;
+  left: 50%;
+  transform: translateX(-50%);
+  text-align: center;
+  max-width: $width;
+  overflow: hidden;
+  max-height: 0;
+  transition: 0.3s all ease;
+  z-index: 9;
+
+  .swiper-container {
+    width: 100%;
+    position: relative;
+    margin: 0 auto;
+
+    > ul {
+      > li {
+        white-space: nowrap;
+
+        > span,
+        > div > span {
+          cursor: pointer;
+          display: inline-block;
+          color: rgba(255, 255, 255, 0.6);
+        }
+
+        &.loopspan {
+          > span,
+          > div > span {
+            animation: 10s wordsLoop linear infinite normal;
+          }
+        }
+
+        &.active {
+          > span,
+          > div > span {
+            color: rgba(255, 255, 255, 1);
+          }
+        }
+      }
+    }
+  }
+
+  .top-con {
+    margin: 0 auto 10px;
+    padding: 10px 0;
+    background: linear-gradient(
+      268deg,
+      rgba(0, 0, 0, 0) 0%,
+      rgba(0, 0, 0, 0.4) 25%,
+      rgba(0, 0, 0, 0.4) 75%,
+      rgba(0, 0, 0, 0) 100%
+    );
+  }
+
+  #swcatalogRoot {
+    > ul {
+      > li {
+        width: 104px;
+        background: rgba(0, 0, 0, 0.5);
+        border-radius: 4px;
+        padding: 4px 10px;
+        border: 1px solid rgba(255, 255, 255, 0.5);
+        box-sizing: border-box;
+        overflow: hidden;
+
+        > span {
+          width: 100%;
+          word-break: keep-all;
+        }
+
+        &.active {
+          border: 1px solid rgba(255, 255, 255, 1);
+        }
+      }
+    }
+  }
+
+  #swSecondary {
+    margin: 20px auto 10px;
+
+    > ul {
+      > li {
+        width: 84px;
+        box-sizing: border-box;
+        overflow: hidden;
+        padding-bottom: 6px;
+
+        > span {
+          width: 100%;
+          word-break: keep-all;
+        }
+
+        &.active {
+          position: relative;
+
+          &::before {
+            content: "";
+            display: inline-block;
+            position: absolute;
+            bottom: 0;
+            width: 20px;
+            height: 2px;
+            z-index: 9999;
+            left: 50%;
+            transform: translateX(-50%);
+            background: var(--colors-primary-base);
+          }
+        }
+      }
+    }
+  }
+
+  #swScenes {
+    > ul {
+      > li {
+        cursor: pointer;
+        width: 72px;
+        height: 72px;
+        border-radius: 6px;
+        border: 1px solid #ffffff;
+        background-size: cover;
+        position: relative;
+        overflow: hidden;
+
+        .iconfont {
+          position: absolute;
+          left: 4px;
+          top: 4px;
+          z-index: 99;
+
+          &::after {
+            background: rgba(0, 0, 0, 0.3);
+            content: "";
+            width: 14px;
+            height: 14px;
+            display: inline-block;
+            position: absolute;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            z-index: -1;
+            filter: blur(4px);
+          }
+        }
+
+        > div {
+          position: absolute;
+          bottom: 0;
+          left: 0;
+          height: 20px;
+          background: rgba(0, 0, 0, 0.5);
+          width: 100%;
+          overflow: hidden;
+
+          > span,
+          div {
+            // width: 100%;
+            line-height: 20px;
+            word-break: keep-all;
+            white-space: normal;
+          }
+        }
+
+        &.active {
+          border: 1px solid var(--colors-primary-base);
+
+          > div {
+            > span {
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.barshow {
+  max-height: 190px;
+}
+
+@keyframes wordsLoop {
+  0% {
+    transform: translateX(100%);
+    -webkit-transform: translateX(100%);
+  }
+  100% {
+    transform: translateX(-180%);
+    -webkit-transform: translateX(-180%);
+  }
+}
+.marquee {
+  .marquee-text-wrap {
+    height: 20px;
+    line-height: 20px;
+  }
+}
+</style>
+<style>
+.marquee-text-text {
+  padding: 0 5px;
+}
+</style>

+ 324 - 459
packages/qjkankan-view/src/components/UIGather/list.vue

@@ -1,171 +1,101 @@
 <template>
-  <div
-    class="bar-list"
-    v-if="
-      show &&
-      !(
-        metadata.catalogRoot &&
-        metadata.catalogRoot.length == 1 &&
-        scenes.length == 1 &&
-        secondaryList.length == 1
-      )
-    "
-    :class="{ barshow: isShowScenesList }"
-  >
-    <div class="top-con">
-      <div
-        class="swiper-container swiper1"
-        :style="`width:calc(100% - 20px)`"
-        id="swScenes"
-        v-if="currentScenesList.length > 0"
-      >
-        <ul class="swiper-wrapper">
-          <li
-            @click="tabCurrentScene(item)"
-            class="swiper-slide"
+  <div class="bar-list" v-if="metadata?.navigationTrees?.length">
+    <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
+            class="swiper-slide scene-slide"
             :class="{
-              active: currentScene.sceneCode == item.sceneCode,
+              active: currentScene.id == item.id ||currentScene.id == item.sid  ,
+              disabled: isLockV4Scene,
               // loopspan:
               //   item.sceneTitle.length > spanlength &&
               //   currentScene.id == item.id,
             }"
-            :style="{ backgroundImage: `url(${item.icon})` }"
-            v-for="(item, i) in currentScenesList"
-            :key="i"
-          >
-            <i
-              class="iconfont"
-              :class="
-                item.type == '4dkk' ? 'icon-editor_3d' : 'icon-editor_panoramic'
-              "
-            ></i>
-            <div class="marquee">
-              <marquee-text
-                :repeat="1"
-                :duration="Math.ceil(item.sceneTitle.length / 10) * 5"
-                :key="item.id"
-                v-if="
-                  item.sceneTitle.length > spanlength &&
-                  currentScene.id == item.id
-                "
-              >
-                {{ item.sceneTitle }}
-              </marquee-text>
-              <span v-else>
-                {{ item.sceneTitle }}
-              </span>
-            </div>
-          </li>
-        </ul>
-      </div>
-
-      <div
-        class="swiper-container swiper2"
-        id="swSecondary"
-        :style="`width:${clamp(secondaryW, 0, 1150)}px`"
-        v-if="secondaryList.length > 1"
-      >
-        <!-- {{ clamp(secondaryW, 0, 1150) }} -->
-        <ul class="swiper-wrapper">
-          <li
-            class="swiper-slide"
-            @click="tabSecondary(item, i)"
+            v-for="(item, index) in currentScenesList"
+          > -->
+          <div
+            class="swiper-slide scene-slide"
             :class="{
-              active: currentSecondary.id == item.id,
+              active: currentScene.id == item.id || (currentScene.sid && currentScene.sid == item.sid),
+
               // loopspan:
-              //   fixTitle(item.name).length > spanlength &&
-              //   currentSecondary.id == item.id,
+              //   item.sceneTitle.length > spanlength &&
+              //   currentScene.id == item.id,
             }"
-            v-for="(item, i) in secondaryList"
-            :key="i"
+            v-for="(item, index) in currentScenesList"
           >
-            <!-- {{ Math.ceil(fixTitle(item.name).length / 10) }} -->
-
-            <marquee-text
-              :duration="Math.ceil(fixTitle(item.name).length / 10) * 5"
-              :key="item.id"
-              :repeat="1"
-              v-if="
-                fixTitle(item.name).length > spanlength &&
-                currentSecondary.id == item.id
-              "
-            >
-              {{ fixTitle(item.name) }}
-            </marquee-text>
-            <span v-else>
-              {{ fixTitle(item.name) }}
-            </span>
-            <!-- <span v-if="currentSecondary.id == item.id">{{
-              fixTitle(item.name)
-            }}</span>
-            <span v-else>{{
-              fixTitle(item.name).length > spanlength
-                ? fixTitle(item.name).slice(0, spanlength)
-                : fixTitle(item.name)
-            }}</span> -->
-          </li>
-        </ul>
+            <div @click="tabCurrentScene(item, index)" class="scene-content" :style="`background-image:url(${item.icon});`">
+              <!-- <img :src="i.icon" alt="" /> -->
+
+              <i class="iconfont" :class="item.type == '4dkk' ? 'icon-editor_3d' : 'icon-editor_panoramic'"></i>
+              <div class="marquee">
+                <marquee-text :repeat="1" :duration="Math.ceil(item.name.length / 10) * 5" :key="item.id" v-if="item.name.length > spanlength && currentScene.id == item.id">
+                  {{ item.name }}
+                </marquee-text>
+                <span v-else>
+                  {{ item.name }}
+                </span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="second-group-box" v-if="metadata?.navigationTrees[rootTabIndex]">
+        <div v-if="metadata?.navigationTrees[rootTabIndex]?.children[0]?.type == 'group' && showSecondTab" class="second-group-list swiper-container" ref="second-group-swiper">
+          <div class="swiper-wrapper second-group-wrapper">
+            <template v-for="(item, index) in metadata?.navigationTrees[rootTabIndex]?.children">
+              <div
+                class="swiper-slide second-group-slide"
+                @click="tabSecond(item)"
+                v-if="item.children.length"
+                :class="{ active: currentSecondId == item.id, loopspan: fixTitle(item.name).length > spanlength && currentSecondId == item.id }"
+              >
+                <div class="second-group-content">
+                  <marquee-text :duration="Math.ceil(fixTitle(item.name).length / 10) * 5" :key="item.id" :repeat="1" v-if="fixTitle(item.name).length > spanlength && currentSecondId == item.id">
+                    {{ fixTitle(item.name) }}
+                  </marquee-text>
+                  <span v-else>
+                    {{ fixTitle(item.name) }}
+                  </span>
+                </div>
+              </div>
+            </template>
+          </div>
+        </div>
       </div>
     </div>
+    <div class="bottom-com">
+      <div v-if="metadata?.navigationTrees?.length > 1" :style="`width:${catalogRootW}px;`" class="root-group-list swiper-container" ref="root-group">
+        <div class="swiper-wrapper root-group-wrapper">
+          <div
+            class="swiper-slide root-group-slide"
+            :class="{
+              active: currentRootId == item.id,
 
-    <div
-      class="swiper-container"
-      id="swcatalogRoot"
-      :style="`width:${catalogRootW > innerW ? '100%' : catalogRootW + 'px'}`"
-      v-if="metadata.catalogRoot.length > 0 && metadata.catalogs.length > 1"
-    >
-      <ul class="swiper-wrapper" v-if="metadata.catalogRoot.length > 1">
-        <li
-          class="swiper-slide"
-          :class="{
-            active: currentCatalogRoot.id == item.id,
-            // loopspan:
-            //   fixTitle(item.name).length > spanlength &&
-            //   currentCatalogRoot.id == item.id,
-          }"
-          @click="tabRoot(item)"
-          v-for="(item, i) in metadata.catalogRoot"
-          :key="i"
-        >
-          <!-- <span v-if="currentCatalogRoot.id == item.id">{{
-            fixTitle(item.name)
-          }}</span>
-          <span v-else>{{
-            fixTitle(item.name).length > spanlength
-              ? fixTitle(item.name).slice(0, spanlength)
-              : fixTitle(item.name)
-          }}</span> -->
-
-          <marquee-text
-            :duration="Math.ceil(fixTitle(item.name).length / 10) * 5"
-            :key="item.id"
-            :repeat="1"
-            v-if="
-              fixTitle(item.name).length > spanlength &&
-              currentCatalogRoot.id == item.id
-            "
+              loopspan: fixTitle(item.name).length > spanlength && currentRootId.id == item.id,
+            }"
+            v-for="(item, index) in metadata?.navigationTrees"
+            @click="tabRoot(item)"
           >
-            {{ fixTitle(item.name) }}
-          </marquee-text>
-          <span v-else>
-            {{ fixTitle(item.name) }}
-          </span>
-        </li>
-      </ul>
+            <div class="root-group-content">
+              <marquee-text :duration="Math.ceil(fixTitle(item.name).length / 10) * 5" :key="item.id" :repeat="1" v-if="fixTitle(item.name).length > spanlength && currentRootId == item.id">
+                {{ fixTitle(item.name) }}
+              </marquee-text>
+              <span v-else>
+                {{ fixTitle(item.name) }}
+              </span>
+            </div>
+          </div>
+        </div>
+      </div>
     </div>
   </div>
 </template>
 
 <script setup>
-import {
-  ref,
-  watch,
-  computed,
-  onMounted,
-  nextTick,
-  unref,
-  watchEffect,
-} from "vue";
+import { ref, watch, computed, onMounted, nextTick, unref, watchEffect } from "vue";
 import { useStore } from "vuex";
 import { useApp } from "@/app";
 import MarqueeText from "vue-marquee-text-component";
@@ -179,69 +109,62 @@ const spanlength = ref(5);
 const metadata = computed(() => store.getters["scene/metadata"]);
 const scenes = computed(() => store.getters["scene/list"]);
 const currentScene = computed(() => store.getters["scene/currentScene"]);
+const currentSecondId = computed(() => store.getters["scene/currentSecondId"]);
+const currentRootId = computed(() => store.getters["scene/currentRootId"]);
 
-const clamp = computed(
-  () => (num, min, max) => Math.min(Math.max(num, min), max)
-);
+const clamp = computed(() => (num, min, max) => Math.min(Math.max(num, min), max));
 
-const currentCatalogRoot = computed(
-  () => store.getters["scene/currentCatalogRoot"]
-);
-const currentSecondary = computed(
-  () => store.getters["scene/currentSecondary"]
-);
+const currentCatalogRoot = computed(() => store.getters["scene/currentCatalogRoot"]);
+const currentSecondary = computed(() => store.getters["scene/currentSecondary"]);
 
 const secondaryList = computed(() => store.getters["scene/secondaryList"]);
 
-const isShowScenesList = computed(
-  () => store.getters["functions/isShowScenesList"]
-);
+const isShowScenesList = computed(() => store.getters["functions/isShowScenesList"]);
 
-const currentScenesList = computed(
-  () => store.getters["scene/currentScenesList"]
-);
+const currentScenesList = computed(() => store.getters["scene/currentScenesList"]);
 
 const show = ref(false);
 
+watch(
+  () => currentScenesList.value,
+  () => {
+    nextTick(() => {
+      initSceneSwiper();
+      initRootGroupSwiper();
+      if (metadata.value.navigationTrees[currentRootId.value]?.children[currentSecondId.value]?.type == "group") {
+        initSecondGroupSwiper();
+      }
+    });
+  }
+);
 const swidth = ref({
   swcatalogRoot: 104,
   swSecondary: 84,
   swScenes: 72,
 });
 
-const scenesListW = computed(
-  () => currentScenesList.value.length * (swidth.value["swScenes"] + 10) - 10
-);
-const secondaryW = computed(
-  () => secondaryList.value.length * (swidth.value["swSecondary"] + 10) - 10
-);
-const catalogRootW = computed(
-  () =>
-    metadata.value.catalogRoot.length * (swidth.value["swcatalogRoot"] + 10) -
-    10
-);
-const innerW = computed(() => 1150);
+const SceneSwiper = ref(null);
+const SecondGroupSwiper = ref(null);
+const rootGroupSwiper = ref(null);
 
-const tabCurrentScene = (data) => {
-  console.log("tabCurrentScene", data.id, currentScene.value.id);
-  if (data.id !== currentScene.value.id) {
-    store.commit("scene/setCurrentScene", data);
-    setTimeout(() => {
-      scenesSwiperFocus();
-    }, 300);
-  } else {
-    console.log("重复点击当前导航");
-    // window.alert("alert-test-->重复点击当前导航");
-  }
-};
+const rootTabIndex = computed(() => {
+  console.error(currentRootId.value);
+  return metadata.value && metadata.value?.navigationTrees ? metadata.value?.navigationTrees.findIndex((item) => item.id == currentRootId.value) : 0;
+});
 
-const tabSecondary = (data, index) => {
-  store.commit("scene/setCurrentSecondary", data);
-};
+const secondTabIndex = computed(() => {
+  return metadata.value && metadata.value?.navigationTrees ? metadata.value.navigationTrees[rootTabIndex.value]?.children.findIndex((item) => item.id == currentSecondId.value) : 0;
+});
 
-const tabRoot = (data) => {
-  store.commit("scene/setCurrentCatalogRoot", data);
-};
+const showSecondTab = computed(() => {
+  return metadata.value && metadata.value?.navigationTrees ? metadata.value?.navigationTrees[rootTabIndex.value].children.some((item) => item.id != currentSecondId.value) : false;
+});
+
+const scenesListW = computed(() => currentScenesList.value.length * (swidth.value["swScenes"] + 10));
+const secondaryW = computed(() => metadata.value.navigationTrees[secondTabIndex.value].length * (swidth.value["swSecondary"] + 10));
+const catalogRootW = computed(() => metadata.value.navigationTrees.length * (swidth.value["swcatalogRoot"] + 10));
+
+const innerW = computed(() => 1150);
 
 const fixTitle = (name) => {
   if (name == "默认二级分组") {
@@ -267,323 +190,265 @@ const swiperOptions = {
   },
 };
 
-// const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
+const tabRoot = (item) => {
+  store.commit("scene/setData", { currentRootId: item.id });
+  // changeSceneList();
+};
+const tabSecond = (item) => {
+  store.commit("scene/setData", { currentSecondId: item.id });
+  let sceneList = metadata.value.navigationTrees[rootTabIndex.value].children[secondTabIndex.value].children;
+  store.commit("scene/setCurrentScenesList", sceneList);
+  // this.changeSceneList();
+};
+const changeSceneList = () => {
+  let currentList = null;
+
+  if (metadata.value.navigationTrees[rootTabIndex.value].children.length && metadata.value.navigationTrees[rootTabIndex.value].children[0].type == "group") {
+    store.commit("scene/setData", { currentSecondId: metadata.value.navigationTrees[rootTabIndex.value].children[0].id });
+    currentList = metadata.value.navigationTrees[rootTabIndex.value].children[secondTabIndex.value].children;
+    store.commit("scene/setCurrentScenesList", currentList);
+  }
 
-const initMainSwiper = () => {
+  if (secondTabIndex.value == -1) {
+    console.error("没有二级目录");
+    let rootList = metadata.value.navigationTrees.find((item) => item.id == currentRootId.value);
+    store.commit("scene/setCurrentScenesList", rootList.children);
+  }
   nextTick(() => {
-    if (window.mainNatSwiper) {
-      // window.mainNatSwiper = null;
-      window.mainNatSwiper.update();
-      window.sencordNatSwiper.slideReset();
+    initSceneSwiper();
+    initRootGroupSwiper();
+    if (metadata.value.navigationTrees[currentRootId.value]?.children[currentSecondId.value]?.type == "group") {
+      initSecondGroupSwiper();
     }
-    window.mainNatSwiper = new Swiper("#swcatalogRoot", swiperOptions);
   });
 };
-const initsencordNatSwiper = () => {
+const initSceneSwiper = () => {
+  if (SceneSwiper.value) {
+    SceneSwiper.value.destroy();
+    SceneSwiper.value = null;
+  }
+  if (!currentScenesList.value.length) {
+    return;
+  }
+
   nextTick(() => {
-    console.warn("initsencordNatSwiper");
-    if (window.sencordNatSwiper) {
-      window.sencordNatSwiper.update();
-      window.sencordNatSwiper.slideReset();
-    }
-    window.sencordNatSwiper = new Swiper("#swSecondary", swiperOptions);
+    SceneSwiper.value = new Swiper(".scene-list", swiperOptions);
   });
 };
-const initScenesSwiper = () => {
-  // console.warn("initScenesSwiper");
+const tabCurrentScene = (data, index) => {
+  store.commit("scene/setCurrentScene", data);
+
+  SceneSwiper.value.slideTo(index);
+};
+const initSecondGroupSwiper = () => {
+  if (SecondGroupSwiper.value) {
+    SecondGroupSwiper.value.destroy();
+    SecondGroupSwiper.value = null;
+  }
+
   nextTick(() => {
-    if (window.scenesNatSwiper) {
-      try {
-        window.scenesNatSwiper.slides.length > 0 &&  window.scenesNatSwiper.update();
-        window.scenesNatSwiper.slideReset();
-      } catch (error) {}
-
-      // window.scenesNatSwiper = null;
-    } else {
-      window.scenesNatSwiper = new Swiper("#swScenes", {
-        ...swiperOptions,
-      });
-    }
-    scenesSwiperFocus();
+    SecondGroupSwiper.value = new Swiper(".second-group-list", swiperOptions);
   });
 };
 
-const scenesSwiperFocus = () => {
-  const sceneIndex = Array.from(currentScenesList.value).findIndex(
-    (item) => item.id === currentScene.value.id
-  );
-  if (window.scenesNatSwiper && window.scenesNatSwiper.slides.length > 0) {
-    const index = sceneIndex < 0 ? 0 : sceneIndex;
-    const fIndex = index < 5 ? 0 : index;
-    console.warn("scenesSwiperFocus", fIndex);
-    window.scenesNatSwiper.slideTo(fIndex);
+const tabCurrentSecondGroup = (data, index) => {
+  // store.commit("scene/setCurrentScene", data);
+
+  SecondGroupSwiper.value.slideTo(index);
+};
+
+const initRootGroupSwiper = () => {
+  // if (rootGroupSwiper.value) {
+  //   rootGroupSwiper.value.destroy();
+  //   rootGroupSwiper.value = null;
+  // }
+  // nextTick(() => {
+  //   rootGroupSwiper.value = new Swiper(".root-group-list", swiperOptions);
+  // });
+
+  if (!rootGroupSwiper.value) {
+    rootGroupSwiper.value = new Swiper(".root-group-list", swiperOptions);
   }
 };
 
-const sencordNatSwiperFocus = () => {
-  nextTick(() => {
-    const current = Array.from(secondaryList.value).findIndex(
-      (item) => item.id === currentSecondary.value.id
-    );
-    if (window.sencordNatSwiper) {
-      const index = current < 0 ? 0 : current;
-      console.warn("sencordNatSwiperFocus", index);
-      // window.sencordNatSwiper.slideTo(current);
-      window.sencordNatSwiper.slideTo(current);
-    }
-  });
+const tabCurrentRootGroup = (data, index) => {
+  // store.commit("scene/setCurrentScene", data);
+
+  SecondGroupSwiper.value.slideTo(index);
 };
 
 onMounted(() => {
   useApp().then(async (app) => {
     show.value = true;
-  });
-  watchEffect(() => {
-    if (
-      metadata.value.catalogRoot &&
-      unref(metadata.value.catalogRoot).length > 0
-    ) {
-      initMainSwiper();
-    }
-  });
-
-  watch([currentSecondary, secondaryList], () => {
-    if (unref(secondaryList).length > 1) {
-      initsencordNatSwiper();
-      sencordNatSwiperFocus();
-    } else {
-      if (window.sencordNatSwiper) {
-        console.warn("destroy-sencordNatSwiper");
-        window.sencordNatSwiper.update();
-        window.sencordNatSwiper.slideReset();
-      }
-    }
-  });
-
-  watch(currentScenesList, () => {
-    initScenesSwiper();
-  });
-  watch(currentCatalogRoot, (val) => {
-    if (Array.from(unref(val).children).includes(currentScene.value.category)) {
-      //当前场景在一类的children
-      const activeSecond = Array.from(unref(secondaryList)).find(
-        (i) => i.id === currentScene.value.category
-      );
-      // console.log("activeSecond", activeSecond);
-      store.commit("scene/setCurrentSecondary", activeSecond);
-      if (window.sencordNatSwiper) {
-        window.sencordNatSwiper.update();
-      }
-    }
+    console.error("app", show.value);
   });
 });
 </script>
 
-<style lang="scss" scoped>
-$width: 1150px;
+<style lang="less" scoped>
+@width: 1150px;
+.swiper-slide {
+  cursor: pointer;
+  &.loopspan {
+    > span,
+    > div > span {
+      animation: 5s wordsLoop linear infinite normal;
+    }
+  }
+}
 
 .bar-list {
   position: absolute;
-  bottom: 68px;
+  bottom: 28px;
   left: 50%;
   transform: translateX(-50%);
   text-align: center;
-  max-width: $width;
+  max-width: @width;
   overflow: hidden;
-  max-height: 0;
   transition: 0.3s all ease;
-  z-index: 9;
-
-  .swiper-container {
-    width: 100%;
-    position: relative;
-    margin: 0 auto;
-
-    > ul {
-      > li {
-        white-space: nowrap;
-
-        > span,
-        > div > span {
+  .top-con {
+    display: inline-block;
+    margin: 0 auto 10px;
+    padding: 10px 6px;
+    overflow: hidden;
+    background: linear-gradient(268deg, transparent, rgba(0, 0, 0, 0.4) 25%, rgba(0, 0, 0, 0.4) 75%, transparent);
+    .scene-list {
+      max-width: @width;
+      margin: 0 auto;
+      // display: inline-block;
+
+      .scene-wrapper {
+        .scene-slide {
+          margin: 0 5px;
+          // white-space: nowrap;
           cursor: pointer;
-          display: inline-block;
-          color: rgba(255, 255, 255, 0.6);
-        }
-
-        &.loopspan {
-          > span,
-          > div > span {
-            animation: 10s wordsLoop linear infinite normal;
+          width: 72px;
+          height: 72px;
+          border-radius: 6px;
+          border: 1px solid #fff;
+          background-size: cover;
+          position: relative;
+          overflow: hidden;
+          &.active {
+            border: 1px solid #0076f6;
+            .marquee {
+              color: #fff !important;
+            }
           }
-        }
-
-        &.active {
-          > span,
-          > div > span {
-            color: rgba(255, 255, 255, 1);
+          .scene-content {
+            width: 100%;
+            height: 100%;
+            background-size: cover;
+            position: relative;
+
+            img {
+              width: 100%;
+              height: 100%;
+              pointer-events: none;
+              object-fit: cover;
+            }
+            > .iconfont {
+              position: absolute;
+              left: 4px;
+              top: 4px;
+              z-index: 99;
+              text-shadow: 0px 0px 4px rgb(0, 0, 0, 0.3);
+            }
+            .marquee {
+              position: absolute;
+              bottom: 0;
+              left: 0;
+              height: 20px;
+              background: rgba(0, 0, 0, 0.5);
+              width: 100%;
+              overflow: hidden;
+              color: rgba(255, 255, 255, 0.6);
+              > span {
+                width: 100%;
+                line-height: 20px;
+                word-break: keep-all;
+                display: inline-block;
+              }
+            }
           }
         }
       }
     }
-  }
-
-  .top-con {
-    margin: 0 auto 10px;
-    padding: 10px 0;
-    background: linear-gradient(
-      268deg,
-      rgba(0, 0, 0, 0) 0%,
-      rgba(0, 0, 0, 0.4) 25%,
-      rgba(0, 0, 0, 0.4) 75%,
-      rgba(0, 0, 0, 0) 100%
-    );
-  }
-
-  #swcatalogRoot {
-    > ul {
-      > li {
-        width: 104px;
-        background: rgba(0, 0, 0, 0.5);
-        border-radius: 4px;
-        padding: 4px 10px;
-        border: 1px solid rgba(255, 255, 255, 0.5);
-        box-sizing: border-box;
-        overflow: hidden;
-
-        > span {
-          width: 100%;
-          word-break: keep-all;
-        }
 
-        &.active {
-          border: 1px solid rgba(255, 255, 255, 1);
-        }
-      }
-    }
-  }
-
-  #swSecondary {
-    margin: 20px auto 10px;
-
-    > ul {
-      > li {
-        width: 84px;
-        box-sizing: border-box;
-        overflow: hidden;
-        padding-bottom: 6px;
-
-        > span {
-          width: 100%;
-          word-break: keep-all;
-        }
-
-        &.active {
-          position: relative;
-
-          &::before {
-            content: "";
-            display: inline-block;
-            position: absolute;
-            bottom: 0;
-            width: 20px;
-            height: 2px;
-            z-index: 9999;
-            left: 50%;
-            transform: translateX(-50%);
-            background: var(--colors-primary-base);
+    .second-group-box {
+      .second-group-list {
+        max-width: @width;
+        margin: 0 auto;
+        display: inline-block;
+
+        .second-group-wrapper {
+          .second-group-slide {
+            width: 84px;
+            box-sizing: border-box;
+            overflow: hidden;
+            padding-bottom: 6px;
+            cursor: pointer;
+            margin: 0 5px;
+            white-space: nowrap;
+            color: hsla(0, 0%, 100%, 0.6);
+            margin: 20px auto 10px;
+            &.active {
+              color: #fff;
+
+              &::before {
+                content: "";
+                display: inline-block;
+                position: absolute;
+                bottom: 0;
+                width: 20px;
+                height: 2px;
+                z-index: 9999;
+                left: 50%;
+                transform: translateX(-50%);
+                background: #0076f6;
+              }
+            }
+            .second-group-content {
+              // width: 100%;
+              // height: 100%;
+              // background-size: cover;
+              // position: relative;
+            }
           }
         }
       }
     }
   }
-
-  #swScenes {
-    > ul {
-      > li {
-        cursor: pointer;
-        width: 72px;
-        height: 72px;
-        border-radius: 6px;
-        border: 1px solid #ffffff;
-        background-size: cover;
-        position: relative;
-        overflow: hidden;
-
-        .iconfont {
-          position: absolute;
-          left: 4px;
-          top: 4px;
-          z-index: 99;
-
-          &::after {
-            background: rgba(0, 0, 0, 0.3);
-            content: "";
-            width: 14px;
-            height: 14px;
-            display: inline-block;
-            position: absolute;
-            top: 50%;
-            left: 50%;
-            transform: translate(-50%, -50%);
-            z-index: -1;
-            filter: blur(4px);
-          }
-        }
-
-        > div {
-          position: absolute;
-          bottom: 0;
-          left: 0;
-          height: 20px;
+  .bottom-com {
+    .root-group-list {
+      max-width: @width;
+      margin: 0 auto;
+      .swiper-wrapper {
+      }
+      .root-group-wrapper {
+        .root-group-slide {
+          width: 104px;
           background: rgba(0, 0, 0, 0.5);
-          width: 100%;
+          border-radius: 4px;
+          padding: 4px 10px;
+          border: 1px solid hsla(0, 0%, 100%, 0.5);
+          box-sizing: border-box;
           overflow: hidden;
+          margin: 0 5px;
+          white-space: nowrap;
+          color: hsla(0, 0%, 100%, 0.6);
 
-          > span,
-          div {
-            // width: 100%;
-            line-height: 20px;
-            word-break: keep-all;
-            white-space: normal;
+          &.active {
+            border: 1px solid #fff;
+            color: #fff;
           }
-        }
-
-        &.active {
-          border: 1px solid var(--colors-primary-base);
-
-          > div {
-            > span {
-            }
+          .root-group-content {
+            width: 100%;
+            word-break: keep-all;
           }
         }
       }
     }
   }
 }
-
-.barshow {
-  max-height: 190px;
-}
-
-@keyframes wordsLoop {
-  0% {
-    transform: translateX(100%);
-    -webkit-transform: translateX(100%);
-  }
-  100% {
-    transform: translateX(-180%);
-    -webkit-transform: translateX(-180%);
-  }
-}
-.marquee {
-  .marquee-text-wrap {
-    height: 20px;
-    line-height: 20px;
-  }
-}
-</style>
-<style>
-.marquee-text-text {
-  padding: 0 5px;
-}
 </style>

+ 441 - 0
packages/qjkankan-view/src/components/UIGather/new-list.vue

@@ -0,0 +1,441 @@
+<template>
+  <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
+            class="swiper-slide scene-slide"
+            :class="{
+              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 currentScenesList"
+          >
+            <div @click="tabCurrentScene(item, index)" class="scene-content" :style="`background-image:url(${item.icon});`">
+              <!-- <img :src="i.icon" alt="" /> -->
+
+              <i class="iconfont" :class="item.type == '4dkk' ? 'icon-editor_3d' : 'icon-editor_panoramic'"></i>
+              <div class="marquee">
+                <marquee-text :repeat="1" :duration="Math.ceil(item.name.length / 10) * 5" :key="item.id" v-if="item.name.length > spanlength && currentScene.id == item.id">
+                  {{ item.name }}
+                </marquee-text>
+                <span v-else>
+                  {{ item.name }}
+                </span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="second-group-box">
+        <div v-if="info.navigationTrees[rootTabIndex]?.children[0]?.type == 'group' && showSecondTab" class="second-group-list swiper-container" ref="second-group-swiper">
+          <div class="swiper-wrapper second-group-wrapper">
+            <div
+              class="swiper-slide second-group-slide"
+              @click="tabSecond(item)"
+              v-if="item.children.length"
+              v-for="(item, index) in info.navigationTrees[rootTabIndex].children"
+              :class="{ active: currentSecondId == item.id, disabled: isLockV4Scene, loopspan: fixTitle(item.name).length > spanlength && currentSecondId == item.id }"
+            >
+              <div class="second-group-content">
+                <marquee-text :duration="Math.ceil(fixTitle(item.name).length / 10) * 5" :key="item.id" :repeat="1" v-if="fixTitle(item.name).length > spanlength && currentSecondId == item.id">
+                  {{ fixTitle(item.name) }}
+                </marquee-text>
+                <span v-else>
+                  {{ fixTitle(item.name) }}
+                </span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="bottom-com">
+      <div v-if="info.navigationTrees.length > 1" :style="`width:${catalogRootW}px;`" class="root-group-list swiper-container" ref="root-group">
+        <div class="swiper-wrapper root-group-wrapper">
+          <div
+            class="swiper-slide root-group-slide"
+            :class="{
+              active: currentRootId == item.id,
+              disabled: isLockV4Scene,
+              loopspan: fixTitle(item.name).length > spanlength && currentRootId.id == item.id,
+            }"
+            v-for="(item, index) in info.navigationTrees"
+            @click="tabRoot(item)"
+          >
+            <div class="root-group-content">
+              <marquee-text :duration="Math.ceil(fixTitle(item.name).length / 10) * 5" :key="item.id" :repeat="1" v-if="fixTitle(item.name).length > spanlength && currentRootId == item.id">
+                {{ fixTitle(item.name) }}
+              </marquee-text>
+              <span v-else>
+                {{ fixTitle(item.name) }}
+              </span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters, mapState } from "vuex";
+import { debounce } from "lodash";
+import MarqueeText from "vue-marquee-text-component";
+export default {
+  components: { MarqueeText },
+  data() {
+    return {
+      spanlength: 6,
+      swidth: {
+        swcatalogRoot: 104,
+        swSecondary: 84,
+        swScenes: 72,
+      },
+      SceneSwiper: null,
+      SecondGroupSwiper: null,
+      rootGroupSwiper: null,
+      swiperOptions: {
+        slidesPerView: "auto",
+        centeredSlides: true,
+        centerInsufficientSlides: true,
+        centeredSlidesBounds: true,
+        freeMode: {
+          enabled: true,
+          sticky: false,
+        },
+      },
+    };
+  },
+
+  watch: {
+    currentScenesList(val) {
+      this.$nextTick(() => {
+        this.initSceneSwiper();
+        this.initRootGroupSwiper();
+        if (this.info.navigationTrees[this.currentRootId]?.children[this.currentSecondId]?.type == "group") {
+          this.initSecondGroupSwiper();
+        }
+      });
+    },
+    "info.navigationTrees": {
+      // immediate: true,
+      handler: function (newVal, oldVal) {
+        if (newVal) {
+          this.$nextTick(() => {
+            // this.changeSceneList();
+          });
+        }
+      },
+      deep: true,
+    },
+  },
+
+  computed: {
+    ...mapState({
+      isLockV4Scene: "isLockV4Scene",
+    }),
+    ...mapGetters({
+      info: "base/baseInfo",
+      currentScene: "scene/currentScene",
+      currentScenesList: "scene/currentScenesList",
+      currentSecondId: "navigation/currentSecondId",
+      currentRootId: "navigation/currentRootId",
+      isEditing: "isEditing",
+    }),
+    scenesListW() {
+      return this?.currentScenesList?.length * (this.swidth["swScenes"] + 10) || 0;
+    },
+    secondaryW() {
+      return this.info.navigationTrees[0].length * (this.swidth["swSecondary"] + 10);
+    },
+    catalogRootW() {
+      // return this.info.navigationTrees.length * (this.swidth["swcatalogRoot"] + 10);
+
+      return this.info.navigationTrees.length * (this.swidth["swcatalogRoot"] + 10);
+    },
+    rootTabIndex() {
+      return this.info.navigationTrees.findIndex((item) => item.id == this.currentRootId);
+    },
+    secondTabIndex() {
+      return this.info.navigationTrees[this.rootTabIndex].children.findIndex((item) => item.id == this.currentSecondId);
+    },
+    showSecondTab() {
+      return this.info.navigationTrees[this.rootTabIndex].children.some((item) => item.id != this.currentSecondId);
+    },
+  },
+  methods: {
+    fixTitle(name) {
+      if (name == "默认二级分组") {
+        name = this.$i18n.t("navigation.default_group_two");
+      } else if (name == "一级分组") {
+        name = this.$i18n.t("navigation.group_one");
+      } else {
+        // eslint-disable-next-line no-self-assign
+        name = name;
+      }
+      return name;
+    },
+    tabRoot(item) {
+      this.$store.commit("navigation/setData", { currentRootId: item.id });
+      this.changeSceneList();
+    },
+    tabSecond(item) {
+      this.$store.commit("navigation/setData", { currentSecondId: item.id });
+      let sceneList = this.info.navigationTrees[this.rootTabIndex].children[this.secondTabIndex].children;
+      this.$store.commit("scene/setCurrentScenesList", sceneList);
+      // this.changeSceneList();
+    },
+    changeSceneList() {
+      let currentList = null;
+
+      if (this.info.navigationTrees[this.rootTabIndex].children.length && this.info.navigationTrees[this.rootTabIndex].children[0].type == "group") {
+        this.$store.commit("navigation/setData", { currentSecondId: this.info.navigationTrees[this.rootTabIndex].children[0].id });
+        currentList = this.info.navigationTrees[this.rootTabIndex].children[this.secondTabIndex].children;
+        this.$store.commit("scene/setCurrentScenesList", currentList);
+      }
+
+      if (this.secondTabIndex == -1) {
+        console.error("没有二级目录");
+        let rootList = this.info.navigationTrees.find((item) => item.id == this.currentRootId);
+        this.$store.commit("scene/setCurrentScenesList", rootList.children);
+      }
+      this.$nextTick(() => {
+        this.initSceneSwiper();
+        this.initRootGroupSwiper();
+        if (this.info.navigationTrees[this.currentRootId]?.children[this.currentSecondId]?.type == "group") {
+          this.initSecondGroupSwiper();
+        }
+      });
+    },
+    initSceneSwiper() {
+      if (this.SceneSwiper) {
+        this.SceneSwiper.destroy();
+        this.SceneSwiper = null;
+      }
+      if (!this.currentScenesList.length) {
+        return;
+      }
+      this.SceneSwiper = new Swiper(".scene-list", this.swiperOptions);
+    },
+
+    tabCurrentScene(data, index) {
+      this.$store.commit("scene/setCurrentScene", data);
+
+      this.SceneSwiper.slideTo(index);
+    },
+    initSecondGroupSwiper() {
+      if (this.SecondGroupSwiper) {
+        this.SecondGroupSwiper.destroy();
+        this.SecondGroupSwiper = null;
+      }
+      this.SecondGroupSwiper = new Swiper(".second-group-list", this.swiperOptions);
+    },
+
+    tabCurrentSecondGroup(data, index) {
+      // this.$store.commit("scene/setCurrentScene", data);
+
+      this.SecondGroupSwiper.slideTo(index);
+    },
+
+    initRootGroupSwiper() {
+      if (this.rootGroupSwiper) {
+        this.rootGroupSwiper.destroy();
+        this.rootGroupSwiper = null;
+      }
+      this.rootGroupSwiper = new Swiper(".root-group-list", this.swiperOptions);
+    },
+
+    tabCurrentRootGroup(data, index) {
+      // this.$store.commit("scene/setCurrentScene", data);
+
+      this.SecondGroupSwiper.slideTo(index);
+    },
+  },
+
+  mounted() {},
+};
+</script>
+
+<style lang="less" scoped>
+@width: 1150px;
+.swiper-slide {
+  cursor: pointer;
+  &.loopspan {
+    > span,
+    > div > span {
+      animation: 5s wordsLoop linear infinite normal;
+    }
+  }
+}
+
+.bar-list {
+  position: absolute;
+  bottom: 28px;
+  left: 50%;
+  transform: translateX(-50%);
+  text-align: center;
+  max-width: @width;
+  overflow: hidden;
+  transition: 0.3s all ease;
+  .top-con {
+    display: inline-block;
+    margin: 0 auto 10px;
+    padding: 10px 6px;
+    overflow: hidden;
+    background: linear-gradient(268deg, transparent, rgba(0, 0, 0, 0.4) 25%, rgba(0, 0, 0, 0.4) 75%, transparent);
+    .scene-list {
+      max-width: @width;
+      margin: 0 auto;
+      // display: inline-block;
+
+      .scene-wrapper {
+        .scene-slide {
+          margin: 0 5px;
+          // white-space: nowrap;
+          cursor: pointer;
+          width: 72px;
+          height: 72px;
+          border-radius: 6px;
+          border: 1px solid #fff;
+          background-size: cover;
+          position: relative;
+          overflow: hidden;
+          &.active {
+            border: 1px solid #0076f6;
+            .marquee {
+              color: #fff !important;
+            }
+          }
+          .scene-content {
+            width: 100%;
+            height: 100%;
+            background-size: cover;
+            position: relative;
+
+            img {
+              width: 100%;
+              height: 100%;
+              pointer-events: none;
+              object-fit: cover;
+            }
+            > .iconfont {
+              position: absolute;
+              left: 4px;
+              top: 4px;
+              z-index: 99;
+              text-shadow: 0px 0px 4px rgb(0, 0, 0, 0.3);
+            }
+            .marquee {
+              position: absolute;
+              bottom: 0;
+              left: 0;
+              height: 20px;
+              background: rgba(0, 0, 0, 0.5);
+              width: 100%;
+              overflow: hidden;
+              color: rgba(255, 255, 255, 0.6);
+              > span {
+                width: 100%;
+                line-height: 20px;
+                word-break: keep-all;
+                display: inline-block;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    .second-group-box {
+      .second-group-list {
+        max-width: @width;
+        margin: 0 auto;
+        display: inline-block;
+
+        .second-group-wrapper {
+          .second-group-slide {
+            width: 84px;
+            box-sizing: border-box;
+            overflow: hidden;
+            padding-bottom: 6px;
+            cursor: pointer;
+            margin: 0 5px;
+            white-space: nowrap;
+            color: hsla(0, 0%, 100%, 0.6);
+            margin: 20px auto 10px;
+            &.active {
+              color: #fff;
+
+              &::before {
+                content: "";
+                display: inline-block;
+                position: absolute;
+                bottom: 0;
+                width: 20px;
+                height: 2px;
+                z-index: 9999;
+                left: 50%;
+                transform: translateX(-50%);
+                background: #0076f6;
+              }
+            }
+            .second-group-content {
+              // width: 100%;
+              // height: 100%;
+              // background-size: cover;
+              // position: relative;
+            }
+          }
+        }
+      }
+    }
+  }
+  .bottom-com {
+    .root-group-list {
+      max-width: @width;
+      margin: 0 auto;
+      .swiper-wrapper {
+      }
+      .root-group-wrapper {
+        .root-group-slide {
+          width: 104px;
+          background: rgba(0, 0, 0, 0.5);
+          border-radius: 4px;
+          padding: 4px 10px;
+          border: 1px solid hsla(0, 0%, 100%, 0.5);
+          box-sizing: border-box;
+          overflow: hidden;
+          margin: 0 5px;
+          white-space: nowrap;
+          color: hsla(0, 0%, 100%, 0.6);
+
+          &.active {
+            border: 1px solid #fff;
+            color: #fff;
+          }
+          .root-group-content {
+            width: 100%;
+            word-break: keep-all;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 3 - 7
packages/qjkankan-view/src/components/assembly/Password.vue

@@ -3,13 +3,7 @@
     <!-- {{ currentScene }} -->
     <img :src="currentScene.icon" alt="" />
 
-    <ui-window
-      @ok="onOk"
-      :okText="$t('common.confirm')"
-      :title="$t('common.tips')"
-      :showCloseIcon="false"
-      :showCancelButton="false"
-    >
+    <ui-window @ok="onOk" :okText="$t('common.confirm')" :title="$t('common.tips')" :showCloseIcon="false" :showCancelButton="false">
       <template v-slot:content>
         <div class="wrapper">
           <ui-input
@@ -64,9 +58,11 @@ const onPasswordChange = (e) => {
 };
 
 watch(passwordkey, () => {
+  console.error("passwordkey.value", passwordkey.value);
   if (passwordkey.value) {
     show.value = true;
   } else {
+    console.error(getApp());
     getApp().Scene.unlock();
   }
 });

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

@@ -2,7 +2,7 @@
   <div v-if="currentScene.type == 'pano'">
     <transition name="fade">
       <div v-if="titleshow" class="titieSlide">
-        {{ currentScene.sceneTitle }}
+        {{ currentScene.name }}
       </div>
     </transition>
   </div>

+ 11 - 13
packages/qjkankan-view/src/hooks/useAudio.js

@@ -13,12 +13,10 @@ const currentAudio = computed(() => store.getters["audio/currentAudio"]);
 const currentAudioTemp = ref("");
 const isDoneforCover = computed(() => store.getters["scene/isDoneforCover"]);
 const currentScene = computed(() => store.getters["scene/currentScene"]);
+const metadata = computed(() => store.getters["scene/metadata"]);
 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
 const isShowCover = computed(() =>
-  store.getters["scene/metadata"].coverInfo &&
-  "isShowCover" in store.getters["scene/metadata"].coverInfo
-    ? store.getters["scene/metadata"].coverInfo.isShowCover === 1
-    : false
+  store.getters["scene/metadata"].coverInfo && "isShowCover" in store.getters["scene/metadata"].coverInfo ? store.getters["scene/metadata"].coverInfo.isShowCover === 1 : false
 );
 
 async function initDefaultAudio() {
@@ -97,11 +95,7 @@ function initAudioPlayer() {
   if (!unref(isInit)) {
     isInit.value = true;
     console.log("initAudioPlayer");
-    const player = createAudioPlayer(
-      unref(currentAudio).url,
-      unref(currentAudio).isAuto,
-      unref(currentAudio).repeat
-    );
+    const player = createAudioPlayer(unref(currentAudio).url, unref(currentAudio).isAuto, unref(currentAudio).repeat);
     currentPlayer.value = player;
     player.on("play", () => {
       console.log("play--22", player.isPlaying);
@@ -120,11 +114,15 @@ function initAudioPlayer() {
 }
 
 function watchUpdateCurrentScenEexplanation(data) {
-  if ("explanation" in data) {
+  // console.error("watchUpdateCurrentScenEexplanation", metadata.value, data);
+  let currentExplanation = metadata.value.workExplanationList.find((item) => item.navigationId == data.id);
+  console.error("currentExplanation", currentExplanation);
+  // if ("explanation" in data) {
+  if (currentExplanation) {
     store.dispatch("audio/initExplanationBGM", {
-      url: data.explanation.audioUrl,
-      repeat: data.explanation.repeat,
-      isAuto: data.explanation.openByDefault,
+      url: currentExplanation.audioUrl,
+      repeat: currentExplanation.repeat,
+      isAuto: currentExplanation.openByDefault,
     });
   } else {
     console.log("not initExplanationBGM");

+ 174 - 126
packages/qjkankan-view/src/pages/show.vue

@@ -31,7 +31,7 @@ import { createApp } from "@/app";
 import { Dialog } from "@/global_components";
 
 import { ref, onMounted, computed, watch, nextTick, unref } from "vue";
-import { getPanoInfo, checkWork, exchangeId } from "@/apis";
+import { getPanoInfo, checkWork, exchangeId, getWorkInfo } from "@/apis";
 import { useStore } from "vuex";
 import config from "@/utils/config";
 import browser from "@/utils/browser";
@@ -48,39 +48,38 @@ const hasPasswordLock = ref(false);
 const lang = getLocale();
 
 const currentScene = computed(() => store.getters["scene/currentScene"]);
-const currentCatalogRoot = computed(
-  () => store.getters["scene/currentCatalogRoot"]
-);
+const currentCatalogRoot = computed(() => store.getters["scene/currentCatalogRoot"]);
 
 const isAutoRotate = computed(() => store.getters["functions/isAutoRotate"]);
 
 const earthMask = computed(() => store.getters["scene/earthMask"]);
 const skyMask = computed(() => store.getters["scene/skyMask"]);
+const hotspotTypeList = computed(() => store.getters["tags/hotspotTypeList"]);
+const hotspotIconTypeList = computed(() => store.getters["tags/hotspotIconTypeList"]);
+const dataType = computed(() => store.getters["tags/dataType"]);
+const hotspots = computed(() => store.getters["tags/hotspots"]);
+
 const isShowOpeningAnimation = ref(0);
 
 onMounted(async () => {
   if (browser.isMobile()) {
-    window.location.href = window.location.href.replace(
-      "show.html",
-      "showMobile.html"
-    );
+    window.location.href = window.location.href.replace("show.html", "showMobile.html");
     return;
   }
 
   const idRes = await exchangeId({
-    id: config.projectNum
-  })
-  const { id, num, calcStatus } = idRes.data
-  config.projectNum = id
+    id: config.projectNum,
+  });
+  const { id, num, calcStatus } = idRes.data;
+  config.projectNum = id;
 
   if (calcStatus === 0) {
-
     Dialog.alert({
       title: t("common.tips"),
-      content: t('common.calcing'),
+      content: t("common.calcing"),
       okText: t("common.confirm"),
     });
-    return
+    return;
   }
 
   let res = await checkWork();
@@ -89,98 +88,137 @@ onMounted(async () => {
     workEnable.value = res.data;
     return;
   }
-  getPanoInfo().then(async (data) => {
-    isShowOpeningAnimation.value = data.isShowOpeningAnimation
-      ? Number(data.isShowOpeningAnimation)
-      : 0;
+  // getWorkInfo().then((res) => {
+  //   console.error(res);
+  // });
+  // getPanoInfo().then(async (data) => {
+  getWorkInfo().then(async (res) => {
+    let data = res.data;
+    let { workOpeningAnimation, work, navigationTrees, workVisualAngleList, workCustomMaskList, workHotList } = data;
+
+    store.commit("tags/setData", { hotspots: workHotList });
+    isShowOpeningAnimation.value = workOpeningAnimation.isShowOpeningAnimation ? Number(workOpeningAnimation.isShowOpeningAnimation) : 0;
     //TODO 兼容1.2.0或以下数据
-    if (
-      !("isShowOpeningAnimation" in data) &&
-      "openingAnimationType" in data &&
-      data.openingAnimationType.length > 0
-    ) {
+    if (!("isShowOpeningAnimation" in workOpeningAnimation) && "openingAnimationType" in workOpeningAnimation && workOpeningAnimation.openingAnimationType.length > 0) {
       console.log("小行星没有开关,但有openingAnimationType强制开启");
       isShowOpeningAnimation.value = 1;
     }
-    store.commit("scene/setScenes", data.scenes);
-    store.commit(
-      "scene/setPassword",
-      data.password === "" ? false : data.password
-    );
-    if (data.password.length > 0) {
+    let scenes = [];
+    navigationTrees.forEach((item) => {
+      item.children.forEach((s_item) => {
+        if (s_item.type != "group") {
+          scenes.push(s_item);
+        }
+        s_item.children.forEach((t_item) => {
+          if (t_item.type != "group") {
+            scenes.push(t_item);
+          }
+        });
+      });
+    });
+    store.commit("scene/setScenes", scenes);
+    store.commit("scene/setPassword", work.password === "" ? false : work.password);
+    if (work.password.length > 0) {
       hasPasswordLock.value = true;
     }
     store.commit("scene/setMetaData", data);
     // document.title = data.name || t("common.no_title");
 
     let firstScene = "";
-
     if (config.sceneNum) {
-      firstScene = data.scenes.find(
-        (item) => item.sceneCode == config.sceneNum
-      );
+      firstScene = scenes.find((item) => item.sceneCode == config.sceneNum);
     } else if (data.firstScene) {
-      firstScene = data.scenes.find(
-        (item) => item.sceneCode == data.firstScene.sceneCode
-      );
+      firstScene = scenes.find((item) => item.sceneCode == data.firstScene.sceneCode);
     }
     // 所有audio入口
 
-    const currentSceneData = firstScene || data.scenes[0];
+    const currentSceneData = firstScene || scenes[0];
 
-    store.dispatch(
-      "audio/initNormalBGM",
-      data.backgroundMusic ? data.backgroundMusic.ossPath : ""
-    );
+    store.dispatch("audio/initNormalBGM", data.workBackgroundMusic ? data.workBackgroundMusic.ossPath : "");
     store.commit("scene/setCurrentScene", currentSceneData);
-
-    // 过滤空分组
-    let ttt = data.catalogRoot.filter((item) => {
-      let flag = "";
-
-      if (item.children) {
-        item.children.some((sub) => {
-          flag = data.scenes.some((son) => {
-            // console.log(String(son.category).toLowerCase(), String(sub).toLowerCase());
-            return (
-              String(son.category).toLowerCase() == String(sub).toLowerCase()
-            );
-          });
-          return flag;
-        });
-      }
-      return flag;
-    });
-
-    data.catalogRoot = ttt;
-
-    let catalog = data.catalogs.find(
-      (item) => item.id == currentScene.value.category
-    );
-
-    // 查询初始场景的所在1级分组
-    data.catalogRoot.forEach((item) => {
-      let temp =
-        item.children && item.children.find((sub) => sub == catalog.id);
-      if (temp) {
-        store.commit("scene/setCurrentCatalogRoot", item);
-        return;
+    let activeScene = null;
+    navigationTrees.forEach((item, index) => {
+      activeScene = item.children.find((pano) => pano.id == currentSceneData.id);
+
+      if (activeScene) {
+        store.commit("scene/setCurrentScenesList", item.children);
+        store.commit("scene/setData", { currentSecondId: null, currentRootId: item.id });
+        // throw new Error("LoopTerminated");
       }
+      item = item.children.forEach((s_item, s_index) => {
+        activeScene = s_item.children.find((pano) => pano.id == currentSceneData.id);
+
+        if (activeScene) {
+          store.commit("scene/setCurrentScenesList", s_item.children);
+          store.commit("scene/setData", { currentSecondId: s_item.id, currentRootId: item.id });
+          // throw new Error("LoopTerminated");
+        }
+        s_item = s_item.children.forEach((t_item, t_index) => {
+          activeScene = t_item.children.find((pano) => pano.id == currentSceneData.id);
+
+          if (activeScene) {
+            store.commit("scene/setCurrentScenesList", s_item.children);
+            store.commit("scene/setData", { currentSecondId: s_item.id, currentRootId: item.id });
+            // throw new Error("LoopTerminated");
+          }
+        });
+      });
     });
 
-    // 查询初始场景的所在2级分组
-    store.commit("scene/setCurrentSecondary", catalog);
-
-    store.commit("functions/setAutoRotate", !!data.isAuto);
+    // 过滤空分组
+    // let ttt = data.catalogRoot.filter((item) => {
+    //   let flag = "";
+
+    //   if (item.children) {
+    //     item.children.some((sub) => {
+    //       flag = data.scenes.some((son) => {
+    //         // console.log(String(son.category).toLowerCase(), String(sub).toLowerCase());
+    //         return String(son.category).toLowerCase() == String(sub).toLowerCase();
+    //       });
+    //       return flag;
+    //     });
+    //   }
+    //   return flag;
+    // });
+
+    // data.catalogRoot = ttt;
+
+    // let catalog = data.catalogs.find((item) => item.id == currentScene.value.category);
+
+    // // 查询初始场景的所在1级分组
+    // data.catalogRoot.forEach((item) => {
+    //   let temp = item.children && item.children.find((sub) => sub == catalog.id);
+    //   if (temp) {
+    //     store.commit("scene/setCurrentCatalogRoot", item);
+    //     return;
+    //   }
+    // });
+
+    // // 查询初始场景的所在2级分组
+    // store.commit("scene/setCurrentSecondary", catalog);
+
+    store.commit("functions/setAutoRotate", !!work.isAuto);
+    console.error("  show.value ", show.value);
 
     show.value = true;
 
-    let isHavePano = data.scenes.some((item) => item.type == "pano");
-
+    let isHavePano = scenes.some((item) => item.type == "pano");
+
+    let currnetVisual = workVisualAngleList.forEach((item) => item.navigationId == currentScene.value.id);
+    // if (!currnetVisual) {
+    //   currnetVisual = {
+    //     hlookat: 0,
+    //     icon: currentScene.value.icon,
+    //     vlookat: 0,
+    //     vlookatmax: 90,
+    //     vlookatmin: -90,
+    //     navigationId: currentScene.value.id,
+    //   };
+    // }
+    // store.commit("scene/setCurrnetVisual", currnetVisual);
     const app = createApp({
       // xml: "%HTMLPATH%/static/template/tour.xml",
-      xml: `${process.env.VUE_APP_CDN}/720yun_fd_manage/${config.projectNum
-        }/tour.xml?rnd=${Math.random()}`,
+      xml: `${process.env.VUE_APP_CDN}/720yun_fd_manage/${config.projectNum}/tour.xml?rnd=${Math.random()}`,
       swf: "%HTMLPATH%/showviewer/lib/krpano/tour.swf",
       target: "pano",
       html5: "auto",
@@ -188,30 +226,18 @@ onMounted(async () => {
       isHavePano,
       vars: {
         startscene: "scene_" + currentScene.value.sceneCode,
-        "view.org_vlookat": currentScene.value.initVisual
-          ? currentScene.value.initVisual.vlookat
-          : 0,
-        "view.org_hlookat": currentScene.value.initVisual
-          ? currentScene.value.initVisual.hlookat
-          : 0,
-        "view.vlookat": currentScene.value.initVisual
-          ? currentScene.value.initVisual.vlookat
-          : 0,
-        "view.hlookat": currentScene.value.initVisual
-          ? currentScene.value.initVisual.hlookat
-          : 0,
-        "autorotate.enabled": !!data.isAuto,
-        "skin_settings.littleplanetintro":
-          typeof data.openingAnimationType === "number"
-            ? data.openingAnimationType
-            : 1,
+        "view.org_vlookat": currnetVisual ? currnetVisual.vlookat : 0,
+        "view.org_hlookat": currnetVisual ? currnetVisual.hlookat : 0,
+        "view.vlookat": currnetVisual ? currnetVisual.vlookat : 0,
+        "view.hlookat": currnetVisual ? currnetVisual.hlookat : 0,
+        "autorotate.enabled": !!work.isAuto,
+        "skin_settings.littleplanetintro": typeof workOpeningAnimation.openingAnimationType === "number" ? workOpeningAnimation.openingAnimationType : 1,
         "skin_settings.lptswitch": unref(isShowOpeningAnimation),
       },
       passQueryParameters: true,
     });
-
     if (app) {
-      coverInfo.value = data.coverInfo || {};
+      coverInfo.value = data.workCoverType || {};
       app.Scene.lock();
       //如果不需要开场封面就直接渲染
       if (!coverInfo.value?.isShowCover) {
@@ -219,23 +245,50 @@ onMounted(async () => {
       }
 
       if (isHavePano) {
+        console.error("isHavePano", hotspots.value);
         app.Scene.on("sceneReady", () => {
           if (app.krpanoDom) {
-            const { sky, earth } = currentScene.value.customMask;
+            let customMask = workCustomMaskList.find((item) => item.navigationId == currentScene.value.id);
+            // const { sky, earth } = currentScene.value.customMask;
+            const { sky, earth } = customMask.data;
             handleMasksUpdate(sky, earth, app);
-            app.krpanoDom.set(
-              `layer[webvr_exitbutton].html`,
-              t("common.exit_vr")
-            );
+            app.krpanoDom.set(`layer[webvr_exitbutton].html`, t("common.exit_vr"));
           }
-          let hotspots = [];
-          if (currentScene.value.someData) {
-            hotspots =
-              typeof currentScene.value.someData == "string"
-                ? JSON.parse(currentScene.value.someData).hotspots
-                : currentScene.value.someData.hotspots;
+          // let hotspots = [];
+          // if (currentScene.value.someData) {
+          //   hotspots = typeof currentScene.value.someData == "string" ? JSON.parse(currentScene.value.someData).hotspots : currentScene.value.someData.hotspots;
+          // }
+          console.error("sceneReady", hotspots.value);
+          let currentHotspots = hotspots.value.filter((item) => item.navigationId == currentScene.value.id);
+
+          if (currentHotspots.length) {
+            // hotspots.forEach((item, index) => {
+            //   if (item.content) {
+            //     let hotSpotType = item.hotspotType;
+            //     for (let key in hotspotTypeList.value) {
+            //       let data = hotspotTypeList.value[key];
+            //       if (key == hotSpotType && item.content[data]) {
+            //         item[data] = item.content[data];
+            //       } else if (data) {
+            //         item[data] = dataType.value[data];
+            //       }
+            //     }
+
+            //     let hotSpotIconType = item.hotspotIconType;
+            //     for (let key in hotspotIconTypeList.value) {
+            //       let data = hotspotIconTypeList.value[key];
+            //       if (key == hotSpotIconType && item.content[data]) {
+            //         item[data] = item.content[data];
+            //       } else if (data) {
+            //         item[data] = dataType.value[data];
+            //       }
+            //     }
+            //   }
+            // });
+
+            app.Tags.initHotspot(currentHotspots, false);
           }
-          app.Tags.initHotspot(hotspots, false);
+          // app.Tags.initHotspot(hotspots, false);
           handleVisualLimit(app, currentScene.value);
         });
       }
@@ -249,11 +302,12 @@ const handlePass = () => {
   hasPasswordLock.value = false;
 };
 const handleVisualLimit = (app, currentScene) => {
-  const { vlookatmax, vlookatmin } = currentScene.initVisual;
+  let currnetVisual = workVisualAngleList.forEach((item) => item.navigationId == currentScene.value.id);
+  // const { vlookatmax, vlookatmin } = currentScene.initVisual;
   // console.log('initVisual',currentScene.initVisual)
   app.krpanoDom.set(`view.limitview`, "lookat");
-  app.krpanoDom.set(`view.vlookatmin`, vlookatmin);
-  app.krpanoDom.set(`view.vlookatmax`, vlookatmax);
+  app.krpanoDom.set(`view.vlookatmin`, currnetVisual.vlookatmin || -90);
+  app.krpanoDom.set(`view.vlookatmax`, currnetVisual.vlookatmax || 90);
 };
 
 const handleMasksUpdate = (skyMask, earthMask, app) => {
@@ -276,16 +330,13 @@ const handleMasksUpdate = (skyMask, earthMask, app) => {
     if ("antidistorted" in skyMask) {
       app.krpanoDom.set(`hotspot[peaklogo].distorted`, skyMask.antidistorted);
       if (!skyMask.antidistorted) {
-        app.krpanoDom.set(`hotspot[peaklogo].scale`, skyMask.scale * 0.50);
+        app.krpanoDom.set(`hotspot[peaklogo].scale`, skyMask.scale * 0.5);
       }
     }
   }
   if (earthMask) {
     if ("isShow" in earthMask) {
-      app.krpanoDom.set(
-        `hotspot[nadirlogo].visible`,
-        Boolean(earthMask.isShow)
-      );
+      app.krpanoDom.set(`hotspot[nadirlogo].visible`, Boolean(earthMask.isShow));
     }
     if (earthMask.icon) {
       app.krpanoDom.set(`hotspot[nadirlogo].url`, earthMask.icon);
@@ -294,12 +345,9 @@ const handleMasksUpdate = (skyMask, earthMask, app) => {
       app.krpanoDom.set(`hotspot[nadirlogo].scale`, earthMask.scale);
     }
     if ("antidistorted" in earthMask) {
-      app.krpanoDom.set(
-        `hotspot[nadirlogo].distorted`,
-        earthMask.antidistorted
-      );
+      app.krpanoDom.set(`hotspot[nadirlogo].distorted`, earthMask.antidistorted);
       if (!earthMask.antidistorted) {
-        app.krpanoDom.set(`hotspot[nadirlogo].scale`, earthMask.scale * 0.50);
+        app.krpanoDom.set(`hotspot[nadirlogo].scale`, earthMask.scale * 0.5);
       }
     }
   }

+ 8 - 12
packages/qjkankan-view/src/sdk/QJKanKan/index.js

@@ -1,26 +1,22 @@
 import { setup as setupSDK } from "@/sdk/QJKanKan/modules";
 import Deferred from "@/sdk/utils/Deferred";
-import Emiter from '@/sdk/utils/Emiter'
+import Emiter from "@/sdk/utils/Emiter";
 
-export default class QJKanKan  extends Emiter {
-  static MITT = { Emiter }
+export default class QJKanKan extends Emiter {
+  static MITT = { Emiter };
   static Deferred = Deferred;
 
   constructor(options) {
-    super()
-    setupSDK(this)
+    super();
+    setupSDK(this);
     this.options = {
       ...options,
-    }
+    };
     this.krpanoDom = null;
   }
-  
 
   render() {
-    this.Scene.start()
+    console.error('render')
+    this.Scene.start();
   }
-
-  
-
-
 }

+ 5 - 5
packages/qjkankan-view/src/sdk/QJKanKan/modules/Scene.js

@@ -32,24 +32,21 @@ export default class Scene extends Emiter {
 
   async start() {
     window.onPanoReady = () => {
+      console.error("onPanoReady");
       if (!this.app.krpanoDom) {
         this.app.krpanoDom = document.getElementById("krpanoSWFObject");
       }
       this.emit("ready");
     };
-
     window.onPanoViewChanged = () => {
       this.emit("viewChanged");
     };
-
     window.onNewPano = () => {
       this.emit("onNewPano");
     };
-
     window.onExitVrStatus = () => {
       this.emit("onExitVr");
     };
-
     let settings = {
       "events[skin_events].onloadcomplete": "js(window.onPanoReady());",
       "events[skin_events].onviewchanged": "js(window.onPanoViewChanged());",
@@ -59,7 +56,7 @@ export default class Scene extends Emiter {
     if (this.locked) {
       await this.locked;
     }
-
+    console.error(settings);
     if (this.app.options.isHavePano) {
       // debugger;
       embedpano({
@@ -71,6 +68,9 @@ export default class Scene extends Emiter {
 
         onready: (pano) => {
           // console.log("pano", pano);
+          // if (!this.app.krpanoDom) {
+          //   this.app.krpanoDom = document.getElementById("krpanoSWFObject");
+          // }
           this.emit("ready");
         },
         onerror: function (error) {

+ 25 - 32
packages/qjkankan-view/src/sdk/QJKanKan/modules/Tags.js

@@ -1,5 +1,5 @@
 import Emiter from "@/sdk/utils/Emiter";
-import { convertJQHotspot } from './hotspot'
+import { convertJQHotspot } from "./hotspot";
 import browser from "@/utils/browser";
 export default class Tags extends Emiter {
   constructor(app) {
@@ -7,16 +7,14 @@ export default class Tags extends Emiter {
     this.app = app;
   }
 
-
   /**
- * 打开热点链接
- */
+   * 打开热点链接
+   */
 
   linkopen(sceneCode, id, hid) {
-    this.emit('clickHotspot', { sceneCode, id })
+    this.emit("clickHotspot", { sceneCode, id });
   }
 
-
   /**
    * 编码转换
    */
@@ -36,17 +34,17 @@ export default class Tags extends Emiter {
     let atv = this.app.krpanoDom.get("curscreen_atv");
 
     this.app.krpanoDom.call(`addImgTextHotSpot(
-        ${param.img.replace('static/', 'showviewer/').replace('.svg', '.png').replace('@2x', '')},
+        ${param.img.replace("static/", "showviewer/").replace(".svg", ".png").replace("@2x", "")},
         ${param.name},
         ${this.htmlEncode(param.hotspotTitle)},
-        ${param.ath != '' ? param.ath : ath},
-        ${param.atv != '' ? param.atv : atv},
-        ${param.secne ? param.secne.sceneCode : 'notjump'},
+        ${param.ath != "" ? param.ath : ath},
+        ${param.atv != "" ? param.atv : atv},
+        ${param.scene ? param.scene.sceneCode : "notjump"},
         ${type},
         ${param.link},
         ${true},
         ${param.visible},
-        ${(param.size * 50) || 1},
+        ${param.size * 50 || 1},
         ${Number(param.fontSize)})`);
   }
   addhotspot(param, type) {
@@ -62,9 +60,9 @@ export default class Tags extends Emiter {
       const hotspot = convertJQHotspot(param);
       // debugger;
       const hotspotStyle = Object.values(hotspot.style);
-      const hotspotString = hotspotStyle.join('|');
-     
-      let hotspotSize
+      const hotspotString = hotspotStyle.join("|");
+      console.error(param)
+      let hotspotSize;
       if (browser.isMobile()) {
         hotspotSize = (Number(hotspot.size) || 1) * 30;
         // console.log(`当前${hotspot.id}基础热点大小`, 30);
@@ -73,27 +71,27 @@ export default class Tags extends Emiter {
         // console.log(`当前${hotspot.id}基础热点大小`, 40);
       }
 
-      const ath = hotspot.ath != '' ? hotspot.ath : this.app.krpanoDom.get("curscreen_ath");
-      const atv = hotspot.atv != '' ? hotspot.atv : this.app.krpanoDom.get("curscreen_atv");
-      let icon = hotspot.icon.replace(/,/g, '|');
+      const ath = hotspot.ath != "" ? hotspot.ath : this.app.krpanoDom.get("curscreen_ath");
+      const atv = hotspot.atv != "" ? hotspot.atv : this.app.krpanoDom.get("curscreen_atv");
+      let icon = hotspot.icon.replace(/,/g, "|");
       const title = this.htmlEncode(hotspot.title);
       const callString = `addJQHotspot(
         ${hotspot.id},
         ${hotspot.type},
         ${title},
-        "${icon.replace('static/', 'showviewer/').replace('.svg', '.png').replace('@2x', '')}",
+        "${icon.replace("static/", "showviewer/").replace(".svg", ".png").replace("@2x", "")}",
         ${ath},
         ${atv},
         "${hotspot.link}",
         ${hotspotSize},
         ${hotspot.visible},
         "${hotspotString}",
-        "${param.secne ? param.secne.sceneCode : 'notjump'}",
+        "${param.scene ? param.scene.sceneCode : "notjump"}",
         )`;
-      // console.log('callString',callString); 
+      // console.log('callString',callString);
       this.app.krpanoDom.call(callString);
     } catch (error) {
-      console.error('error', error);
+      console.error("error", error);
     }
 
     // 设置热点图片默认的偏移值
@@ -105,23 +103,19 @@ export default class Tags extends Emiter {
     //   offset = '-100%'
     // }
     // krpano.set('layer[tooltip_' + param.name + '].y', `${offset}`)
-
   }
 
-
-
-
   /**
-  * 初始化
-  */
+   * 初始化
+   */
 
   initHotspot(hotspots, type) {
-    hotspots.forEach(item => {
-      this.addhotspot(item, type)
+    console.error("hotspots", hotspots);
+    hotspots.forEach((item) => {
+      this.addhotspot(item, type);
     });
   }
 
-
   /**
    * 显示隐藏热点
    */
@@ -130,8 +124,7 @@ export default class Tags extends Emiter {
     try {
       this.app.krpanoDom.call(`set_hotspot_visible(${toggle})`);
     } catch (e) {
-      e
+      e;
     }
   }
-
 }

+ 5 - 4
packages/qjkankan-view/src/sdk/QJKanKan/modules/hotspot.js

@@ -41,10 +41,12 @@ const convertBaseStyle = (dest, origin) => {
     dest.style.fontSize = origin.fontSize;
     dest.style.position = origin.titlePosition;
 
-    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") {
@@ -114,8 +116,7 @@ const coverSerialFrame = (origin) => {
   duplicate.ath = origin.ath;
   duplicate.atv = origin.atv;
   duplicate.type = 2;
-  duplicate.icon =
-    origin.serialFrameInfo.img + "?x-oss-process=image/resize,w_128,q_80" || "";
+  duplicate.icon = origin.serialFrameInfo.img + "?x-oss-process=image/resize,w_128,q_80" || "";
 
   duplicate.link = origin.link || "";
   duplicate.size = origin.size;

+ 14 - 14
packages/qjkankan-view/src/store/modules/scene.js

@@ -38,11 +38,14 @@ export default {
       secondaryList: {},
       //当前场景分组
       currentScenesList: {},
+
       //当时场景的版本
       fdkkCurrentVersion: "v4",
       // 存在开场动作并动作完成的flag
 
       isDoneforCover: false,
+      currentSecondId: null,
+      currentRootId: null,
     };
   },
   getters: {
@@ -50,6 +53,8 @@ export default {
     secondaryList: (state) => state.secondaryList,
     currentCatalogRoot: (state) => state.currentCatalogRoot,
     currentScenesList: (state) => state.currentScenesList,
+    currentSecondId: (state) => state.currentSecondId,
+    currentRootId: (state) => state.currentRootId,
     currentSecondary: (state) => state.currentSecondary,
     currentScene: (state) => state.currentScene,
     fdkkCurrentVersion: (state) => state.fdkkCurrentVersion,
@@ -98,6 +103,11 @@ export default {
     },
   },
   mutations: {
+    setData(state, payload) {
+      for (let key in payload) {
+        state[key] = payload[key];
+      }
+    },
     setScenes(state, payload) {
       state.list = payload;
     },
@@ -113,10 +123,7 @@ export default {
       if (payload.someData) {
         try {
           // someData旧数据有可能是字符串,要parse一下
-          payload.someData =
-            typeof payload.someData == "string"
-              ? JSON.parse(payload.someData)
-              : payload.someData;
+          payload.someData = typeof payload.someData == "string" ? JSON.parse(payload.someData) : payload.someData;
         } catch (error) {}
       }
       state.currentScene = payload;
@@ -167,16 +174,9 @@ export default {
     },
     setMetaData(state, payload) {
       state.metadata = payload;
-      document.title = payload.name;
-      document
-        .querySelector('meta[name="description"]')
-        .setAttribute(
-          "content",
-          payload.description.replace(/<\/?[^>]+(>|$)/g, "")
-        );
-      document
-        .querySelector('meta[name="cover"]')
-        .setAttribute("content", payload.icon);
+      document.title = payload.work.name;
+      document.querySelector('meta[name="description"]').setAttribute("content", payload.work.description.replace(/<\/?[^>]+(>|$)/g, ""));
+      document.querySelector('meta[name="cover"]').setAttribute("content", payload.work.icon);
     },
 
     setDoneforCover(state, payload) {

+ 112 - 3
packages/qjkankan-view/src/store/modules/tags.js

@@ -1,5 +1,4 @@
-
-import { useApp } from '@/app'
+import { useApp } from "@/app";
 
 export default {
   namespaced: true,
@@ -7,13 +6,123 @@ export default {
     return {
       // 当前热点
       currentTag: {},
+      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: "",
+        },
+      },
+      hotspots: [],
     };
   },
   getters: {
     currentTag: (state) => state.currentTag,
-  
+    hotspotTypeList: (state) => state.hotspotTypeList,
+    hotspotIconTypeList: (state) => state.hotspotIconTypeList,
+    dataType: (state) => state.dataType,
+    hotspots: (state, getters, rootState, rootGetters) => {
+      console.error(rootState.scene?.matedata?.workHotList)
+      let hotspots = rootState.scene?.matedata?.workHotList || [];
+      if (hotspots.length && !state.hotspots.length) {
+        state.hotspots = hotspots;
+        console.error(state.hotspots);
+      }
+      if (state.hotspots.length) {
+        state.hotspots.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.hotspots;
+    },
   },
   mutations: {
+    setData(state, payload) {
+      for (let key in payload) {
+        state[key] = payload[key];
+      }
+    },
     setCurrentTag(state, payload) {
       state.currentTag = payload;
     },

+ 4 - 0
packages/qjkankan-view/vue.config.js

@@ -36,6 +36,10 @@ module.exports = defineConfig({
         target: process.env.VUE_APP_PROXY_URL_ROOT,
         changeOrigin: true,
       },
+      "/work": {
+        target: proxy_url,
+        changeOrigin: true,
+      },
     },
   },
 });