tremble 2 år sedan
förälder
incheckning
e652ca9e9a
54 ändrade filer med 3736 tillägg och 1373 borttagningar
  1. 1397 428
      package-lock.json
  2. 4 4
      package.json
  3. 0 1
      packages/qjkankan-editor/.env
  4. 0 1
      packages/qjkankan-editor/.env.bendi
  5. 0 1
      packages/qjkankan-editor/.env.prod
  6. 0 1
      packages/qjkankan-editor/.env.testprod
  7. 0 4
      packages/qjkankan-editor/.eslintrc.js
  8. 0 9
      packages/qjkankan-editor/babel.config.js
  9. 4 4
      packages/qjkankan-editor/package-lock.json
  10. 46 0
      packages/qjkankan-editor/package_back.json
  11. 4 0
      packages/qjkankan-editor/public/edit.html
  12. 13 0
      packages/qjkankan-editor/public/static/lib/swiper/swiper-bundle.min.css
  13. 14 0
      packages/qjkankan-editor/public/static/lib/swiper/swiper-bundle.min.js
  14. 7 9
      packages/qjkankan-editor/public/static/template/skin/vtourskin.xml
  15. 3 1
      packages/qjkankan-editor/src/Store/index.js
  16. 6 0
      packages/qjkankan-editor/src/Store/modules/index.js
  17. 96 0
      packages/qjkankan-editor/src/Store/modules/scene.js
  18. 22 0
      packages/qjkankan-editor/src/Store/modules/tags.js
  19. 1 37
      packages/qjkankan-editor/src/api/index.js
  20. 3 3
      packages/qjkankan-editor/src/components/Snapshot.vue
  21. 4 0
      packages/qjkankan-editor/src/components/audio/audioForEditor.vue
  22. 0 1
      packages/qjkankan-editor/src/config/index.js
  23. 102 80
      packages/qjkankan-editor/src/core/utils.js
  24. 46 43
      packages/qjkankan-editor/src/framework/EditorHead.vue
  25. 14 3
      packages/qjkankan-editor/src/framework/play/index.vue
  26. 323 0
      packages/qjkankan-editor/src/framework/play/pano/components/list.vue
  27. 178 0
      packages/qjkankan-editor/src/framework/play/pano/index.vue
  28. 0 1
      packages/qjkankan-editor/src/mixins/index.js
  29. 30 21
      packages/qjkankan-editor/src/views/explanation/explanationSettings.vue
  30. 9 17
      packages/qjkankan-editor/src/views/hotspot/EditPanel.vue
  31. 14 17
      packages/qjkankan-editor/src/views/hotspot/HotSpotList.vue
  32. 1 0
      packages/qjkankan-editor/src/views/hotspot/index.vue
  33. 12 0
      packages/qjkankan-editor/src/views/screen/Setting.vue
  34. 4 4
      packages/qjkankan-kankan-view/.env
  35. 4 0
      packages/qjkankan-kankan-view/.env.development
  36. 442 6
      packages/qjkankan-kankan-view/package-lock.json
  37. 2 0
      packages/qjkankan-kankan-view/package.json
  38. 3 2
      packages/qjkankan-kankan-view/public/spg.html
  39. 3 1
      packages/qjkankan-kankan-view/src/components/Information/index.vue
  40. 427 313
      packages/qjkankan-kankan-view/src/pages/SMG.vue
  41. 0 8
      packages/qjkankan-kankan-view/src/pages/SPG.vue
  42. 12 32
      packages/qjkankan-kankan-view/src/pages/smg.js
  43. 12 31
      packages/qjkankan-kankan-view/src/pages/spg.js
  44. 2 1
      packages/qjkankan-kankan-view/vue.config.js
  45. 0 18
      packages/qjkankan-view/public/index.html
  46. 4 4
      packages/qjkankan-view/public/static/lib/krpano/plugins/webvr.xml
  47. 19 0
      packages/qjkankan-view/public/static/lib/krpano/tour.xml
  48. 25 0
      packages/qjkankan-view/src/components/Fdkk/index.vue
  49. 37 21
      packages/qjkankan-view/src/components/Pano/index.vue
  50. 2 0
      packages/qjkankan-view/src/components/UIGather/list.vue
  51. 1 0
      packages/qjkankan-view/src/components/UIGather/menu.vue
  52. 1 1
      packages/qjkankan-view/src/components/assembly/Loading.vue
  53. 2 1
      packages/qjkankan-view/src/pages/show.vue
  54. 381 244
      yarn.lock

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1397 - 428
package-lock.json


+ 4 - 4
package.json

@@ -27,13 +27,13 @@
   },
   "lint-staged": {
     "*.js": [
-        "prettier --write"
+      "prettier --write"
     ],
     "*.ts": [
-        "prettier --write"
+      "prettier --write"
     ],
     "*.vue": [
-        "prettier --write"
+      "prettier --write"
     ]
-}
+  }
 }

+ 0 - 1
packages/qjkankan-editor/.env

@@ -1,6 +1,5 @@
 VUE_APP_MAIN_COLOR=''
 VUE_APP_STATIC_DIR=static
-VUE_APP_INNERNET=https://fcb.intranet.4dkankan.com
 VUE_APP_CDN=https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com
 VUE_APP_PROXY_URL_ROOT='https://test.4dkankan.com'
 VUE_APP_PROXY_URL='https://test.4dkankan.com/qjkankan/'

+ 0 - 1
packages/qjkankan-editor/.env.bendi

@@ -1,6 +1,5 @@
 VUE_APP_MAIN_COLOR=''
 VUE_APP_STATIC_DIR=static
-VUE_APP_INNERNET=https://fcb.intranet.4dkankan.com
 VUE_APP_CDN=https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com
 VUE_APP_PROXY_URL='http://192.168.0.135:8001/'
 VUE_APP_URL_FILL='/'

+ 0 - 1
packages/qjkankan-editor/.env.prod

@@ -1,6 +1,5 @@
 VUE_APP_MAIN_COLOR=''
 VUE_APP_STATIC_DIR=static
-VUE_APP_INNERNET=https://fcb.intranet.4dkankan.com
 VUE_APP_CDN=https://4dkk.4dage.com
 VUE_APP_PROXY_URL='http://www.4dkankan.com/qjkankan/'
 VUE_APP_URL_FILL=/qjkankan

+ 0 - 1
packages/qjkankan-editor/.env.testprod

@@ -2,7 +2,6 @@
 NODE_ENV=production
 VUE_APP_MAIN_COLOR=''
 VUE_APP_STATIC_DIR=static
-VUE_APP_INNERNET=https://fcb.intranet.4dkankan.com
 VUE_APP_CDN=https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com
 VUE_APP_PROXY_URL='http://test.4dkankan.com/qjkankan/'
 VUE_APP_URL_FILL=https://test.4dkankan.com/qjkankan/

+ 0 - 4
packages/qjkankan-editor/.eslintrc.js

@@ -2,10 +2,6 @@ module.exports = {
   root: true,
   env: {
     node: true,
-    browser: true,
-    es6: true,
-    commonjs: true,
-    jquery: true,
   },
   'extends': [
     'plugin:vue/essential',

+ 0 - 9
packages/qjkankan-editor/babel.config.js

@@ -1,14 +1,5 @@
 module.exports = {
   presets: [
     '@vue/cli-plugin-babel/preset'
-  ],
-  plugins: [
-    [
-      "component",
-      {
-        "libraryName": "element-ui",
-        "styleLibraryName": "theme-chalk"
-      }
-    ]
   ]
 }

+ 4 - 4
packages/qjkankan-editor/package-lock.json

@@ -1,12 +1,12 @@
 {
-  "name": "qjkankan",
-  "version": "0.1.0",
+  "name": "@qjkankan/editor",
+  "version": "1.2.0",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
-      "name": "qjkankan",
-      "version": "0.1.0",
+      "name": "@qjkankan/editor",
+      "version": "1.2.0",
       "dependencies": {
         "@floating-ui/dom": "^0.5.4",
         "core-js": "^3.8.2",

+ 46 - 0
packages/qjkankan-editor/package_back.json

@@ -0,0 +1,46 @@
+{
+  "name": "@qjkankan/editor",
+  "version": "1.2.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "serve-prod": "vue-cli-service serve --mode prod",
+    "serve-testprod": "vue-cli-service serve --mode testprod",
+    "serve-local": "vue-cli-service serve --mode bendi",
+    "build": "vue-cli-service build",
+    "build-prod": "vue-cli-service build --mode prod",
+    "build-testprod": "vue-cli-service build --mode testprod",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "@floating-ui/dom": "^0.5.4",
+    "element-ui": "^2.15.1",
+    "html2canvas": "^1.4.1",
+    "photoswipe": "^4.1.3",
+    "swiper": "^5.3.8",
+    "v-viewer": "^1.5.1",
+    "video.js": "^7.11.8",
+    "vue-awesome-swiper": "^4.1.1",
+    "vue-cropperjs": "^4.2.0",
+    "vue-i18n": "^8.22.3",
+    "vue-photo-preview": "^1.1.3",
+    "vue-router": "^3.2.0",
+    "vuedraggable": "^2.24.3",
+    "core-js": "^3.6.5",
+    "vue": "^2.6.11",
+    "vuex": "^3.6.0"
+    
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^6.2.2",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "vue-template-compiler": "^2.6.11"
+  }
+}

+ 4 - 0
packages/qjkankan-editor/public/edit.html

@@ -13,6 +13,8 @@
     <link rel="stylesheet" href="<%= VUE_APP_STATIC_DIR %>/lib/animate/animate.min.css"/>
     <link rel="stylesheet" href="<%= VUE_APP_STATIC_DIR %>/lib/mCustomScrollbar/jquery.mCustomScrollbar.min.css"/>
     <link rel="stylesheet" href="<%= VUE_APP_STATIC_DIR %>/lib/scrollbar/perfect-scrollbar.css"/>
+    <link rel="stylesheet" href="<%= VUE_APP_STATIC_DIR %>/lib/swiper/swiper.min.css" />
+
     <title>全景看看作品制作工具</title>
   </head>
   <body>
@@ -22,5 +24,7 @@
     <script src="<%= VUE_APP_STATIC_DIR %>/lib/krpano/js/tour.js"></script>
     <script src="<%= VUE_APP_STATIC_DIR %>/lib/mCustomScrollbar/jquery.mCustomScrollbar.concat.min.js"></script>
     <script src="<%= VUE_APP_STATIC_DIR %>/lib/scrollbar/perfect-scrollbar.min.js"></script>
+    <script src="<%= VUE_APP_STATIC_DIR %>/lib/swiper/swiper.min.js"></script>
+
   </body>
 </html>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 13 - 0
packages/qjkankan-editor/public/static/lib/swiper/swiper-bundle.min.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 14 - 0
packages/qjkankan-editor/public/static/lib/swiper/swiper-bundle.min.js


+ 7 - 9
packages/qjkankan-editor/public/static/template/skin/vtourskin.xml

@@ -23,8 +23,8 @@
     <settings name="auto_thumbs" thumb_size="84" thumb_background_size="90" thumb_spacing="14" left="0" right="0"
               bottom="5" albums_right="0"/>
     <events name="auto_thumbs" keep="true" onresize="resize_auto_thumbs()" onnewscene="update_active_thumb();"
-            onxmlcomplete="ifnot(thumbs_intitialized, create_auto_thumbs(); setup_title(); set(thumbs_intitialized, true););"
-            onmousedown="hide_container(get(layer[albums].current_container)); fadein_children(albums_scrollarea); set(layer[new_thumbs].visible, false); js(tourguishow()); set(layer[albums].current_container, null);"/>
+            onxmlcomplete="ifnot(thumbs_intitialized, create_auto_thumbs();  set(thumbs_intitialized, true););"
+            onmousedown="hide_container(get(layer[albums].current_container)); fadein_children(albums_scrollarea); set(layer[new_thumbs].visible, false); set(layer[albums].current_container, null);"/>
      <layer name="thumbs_background" scalechildren="true" scale="1" type="container" align="leftbottom" x="0" y="-102"
            width="100%" height="102" maskchildren="false" bgcolor="0x000000" bgalpha="0.4" keep="true"
            state="closed" vr="false" ></layer>
@@ -774,7 +774,7 @@
          js(littlePlaneOpen(get(xml.scene))); 
          ,
          init_gyro();
-          set(events[init_view_event].onnewscene,'js(initViewSetting(get(xml.scene)));js(initCompassSetting(get(xml.scene),get(view.hlookat)));js(getComment(get(xml.scene)));js(initHotspotSetting(get(xml.scene)));');
+          set(events[init_view_event].onnewscene,'js(initViewSetting(get(xml.scene)));js(initCompassSetting(get(xml.scene),get(view.hlookat)));js(getComment(get(xml.scene)));');
         ); 
   
         set(layer[skin_layer].visible, true); 
@@ -831,9 +831,7 @@
           set(view.vlookatmax,%3); 
           set(autorotate.horizon,%4);
           js(getComment(get(xml.scene))); 
-          js(initHotspotSetting(get(xml.scene)));
           set(events[init_view_event].onloadcomplete,'js(initViewSetting(get(xml.scene)));js(initCompassSetting(get(xml.scene),get(view.hlookat)));js(getComment(get(xml.scene)));
-          js(initHotspotSetting(get(xml.scene)));');
         );
         delayedcall(3,init_gyro(););
         ); 
@@ -1090,7 +1088,7 @@
         set(layer[skin_video_playpause].state,'hidden'); tween(layer[skin_video_playpause].alpha, 0.0); ); );
     </action>
 <contextmenu fullscreen="false" versioninfo="false">
-        <item name="cc" caption="更改控制模式" onclick="skin_changecontrolmode();" separator="true"/>
+        <!-- <item name="cc" caption="更改控制模式" onclick="skin_changecontrolmode();" separator="true"/>
         <item name="nv" caption="正常视角" onclick="skin_view_normal();" showif="view.vlookatrange == 180"
               separator="true"/>
         <item name="sv" caption="立体视角" onclick="skin_view_stereographic();" showif="view.vlookatrange == 180"
@@ -1100,7 +1098,7 @@
 		<item name="vb" caption="水晶球视角" onclick="skin_view_ball();" showif="view.vlookatrange == 180"
               devices="flash|webgl"/>
 	            <item name="lp" caption="小行星视角" onclick="skin_view_littleplanet();" showif="view.vlookatrange == 180"
-              devices="flash|webgl"/>
+              devices="flash|webgl"/> -->
     </contextmenu>
     <action name="skin_changecontrolmode">switch(control.touch, moveto, drag); switch(control.mouse, moveto, drag);
     </action>
@@ -1304,7 +1302,7 @@
       set(hotspot[get(schp_name)].height,%11);
 
       set(hotspot[get(schp_name)].visible,true);
-	    set(hotspot[get(schp_name)].onhover,showtext(get(hotspottitle),skintext)); 
+	    <!-- set(hotspot[get(schp_name)].onhover,showtext(get(hotspottitle),skintext));  -->
       addhotspot(get(schp_name));
       set(hotspot[get(schp_name)].onclick,'js(__krfn.utils.linkopen(%8,%2));');
 
@@ -1502,7 +1500,7 @@
     </action>
     <settings imagewidth="" imageheight="" objectid="" objectnum=""/>
     <events onresize="updateframeresize(container_obj,get(settings.imagewidth),get(settings.imageheight));"
-            onmousewheel="updateframesscale();js(initHotspotSetting(get(xml.scene)));"/>
+            onmousewheel="updateframesscale();"/>
     <style name="frame" keep="true" visible="false" width="100%" height="100%" scale_o="" align="center"
            onloaded="set(plugin[loadingtext].visible,false); updateframeresize(container_obj,get(imagewidth),get(imageheight));copy(scale_o,scale); copy(settings.imagewidth,imagewidth); copy(settings.imageheight,imageheight);set(layer[container_obj].visible,true);"
            ondown="copy(oldmousex,mouse.x);domouserotate();"

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

@@ -3,6 +3,7 @@ import Vuex from 'vuex'
 
 import browser from "@/utils/browser"
 import { deepClone } from "@/utils/other.js";
+import modules from './modules/'
 
 Vue.use(Vuex)
 
@@ -149,6 +150,7 @@ const store = new Vuex.Store({
     },
     SetInfo(state, data) {
       state.info = data
+      this.commit('scene/setMetaData', data)
       this.commit("BackupInfo", browser.CloneObject(data))
     },
     BackupInfo(state, data) {
@@ -200,7 +202,7 @@ const store = new Vuex.Store({
     },
   },
   modules: {
-
+    ...modules
   }
 })
 

+ 6 - 0
packages/qjkankan-editor/src/Store/modules/index.js

@@ -0,0 +1,6 @@
+import scene from './scene'
+import tags from './tags'
+export default {
+    scene,
+    tags
+}

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

@@ -0,0 +1,96 @@
+export default {
+  namespaced: true,
+  state() {
+    return {
+      // 场景列表
+      list: [],
+      //当前场景
+      currentScene: {},
+      //访问密码
+      password: "",
+      //场景数据
+      metadata: {},
+      //当前一级分组
+      currentCatalogRoot:{},
+      //当前二级分组
+      currentSecondary:{},
+      //二级分组
+      secondaryList:{},
+      //当前场景分组
+      currentScenesList:{},
+
+    };
+  },
+  getters: {
+    list: (state) => state.list,
+    secondaryList: (state) => state.secondaryList,
+    currentCatalogRoot: (state) => state.currentCatalogRoot,
+    currentScenesList: (state) => state.currentScenesList,
+    currentSecondary: (state) => state.currentSecondary,
+    currentScene: (state) => state.currentScene,
+    password: (state) => state.password,
+    metadata: (state) => state.metadata,
+  },
+  mutations: {
+    setScenes(state, payload) {
+      state.list = payload;
+    },
+    setPassword(state, payload) {
+      state.password = payload;
+    },
+
+    // 设置当前场景
+    setCurrentScene(state, payload) {
+      state.currentScene = payload;
+    },
+    // 设置当前二级分组
+    setCurrentSecondary(state, payload) {
+      state.currentSecondary = payload;
+      let arr = state.list.filter((item) => {
+        return state.currentSecondary.id == item.category;
+      });
+
+
+      this.commit('scene/setCurrentScenesList', arr.sort((a, b) => a.weight - b.weight))
+    },
+
+    // 设置当前场景列表
+    setCurrentScenesList(state, payload) {
+      state.currentScenesList = payload;
+    },
+
+    // 设置当前一级分组
+    setCurrentCatalogRoot(state, payload) {
+      state.currentCatalogRoot = payload;
+      console.log(state.metadata.catalogs);
+      let temp = [];
+      payload.children &&
+        payload.children.forEach((item) => {
+          state.metadata.catalogs.forEach((sub) => {
+            if (item == sub.id) {
+              if (state.list.some(iii=>iii.category == sub.id)) {
+                temp.push(sub);
+              }
+            }
+          });
+        });
+
+      console.log(temp,'this.commit');
+
+
+      this.commit('scene/setSecondaryList', temp)
+    },
+
+    // 设置当前二级分组列表
+    setSecondaryList(state, payload){
+      state.secondaryList = payload
+      if (payload.length>0) {
+        this.commit('scene/setCurrentSecondary', payload[0])
+      }
+    },
+    setMetaData(state, payload) {
+      state.metadata = payload;
+      document.title = payload.name || '无标题'
+    },
+  },
+};

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

@@ -0,0 +1,22 @@
+export default {
+  namespaced: true,
+  state() {
+    return {
+      currentEditTag: '',
+      // 是否在确认热点位置状态
+      isConfirmingPosi: false,
+    };
+  },
+  getters: {
+    currentEditTag: (state) => state.currentEditTag,
+    isConfirmingPosi: (state) => state.isConfirmingPosi,
+  },
+  mutations: {
+    setTags(state, payload) {
+      state.currentEditTag = payload;
+    },
+    setIsConfirmingPosi(state, payload) {
+      state.isConfirmingPosi = payload;
+    },
+  },
+};

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

@@ -10,9 +10,7 @@ const scene = function() {
     return config.sceneNum
 }
 
-const HDNumber = function() {
-    return config.hengdaNum
-}
+
 
 const CLIENT_CODE =  config.client_code
 const URL_FILL =  config.urlFill
@@ -394,24 +392,6 @@ export function getAuthCode(data, ok, no) {
     return http.postJson(`/fcb/project/api/query/authCode`, data, ok, no)
 }
 
-/**
- * 获取户型名称列表
- * @param {*} data 
- * @param {*} ok 
- * @param {*} no 
- */
-export function getHouseNameList(data, ok, no) {
-    data.prodId = HDNumber()
-    getAuthCode(data,(res)=>{
-        let tmp = {
-            ...data,
-            authcode:res.data.authcode,
-            req_time:res.data.timeStamp,
-            client_code:CLIENT_CODE
-        }
-        return http.postJson(`/vr/prodvr/prod/v1/details/queryHouseNamesByProdId`, tmp, ok, no)
-    })
-}
 
 /**
  * 获取户型列表
@@ -426,22 +406,6 @@ export function getHouseList(data, ok, no) {
 }
 
 
-
-/**
- * 保存户型
- * @param {*} data 
- * @param {*} ok 
- * @param {*} no 
- */
-export function saveHouse(data, ok, no) {
-    data.houseId = number()
-    data.hengdaId = HDNumber()
-    return http.postJson(`/fcb/pano/scene/saveVrModel`, data, ok, no)
-}
-
-
-
-
 /**
  * 获取全景图列表
  * @param {*} data 

+ 3 - 3
packages/qjkankan-editor/src/components/Snapshot.vue

@@ -36,15 +36,15 @@ export default {
     left: 0;
     top: 0;
     width: 100%;
-    height: 100%;
+    height: calc(100% - 240px);
     pointer-events: none;
     .flash {
         position: absolute;
         left: 0;
         top: 0;
         width: 100%;
-        height: 100%;
-        background-color: rgba(255, 255, 255, 1);
+        height: calc(100% + 240px);
+        background-color: rgba(255, 255, 255, 0.5);
     }
     .frame {
         position: absolute;

+ 4 - 0
packages/qjkankan-editor/src/components/audio/audioForEditor.vue

@@ -139,21 +139,25 @@ export default {
   background: #033d7c;
 
   border-radius: 50%;
+
   .left {
     border-radius: 50%;
     background: @pcolor;
     clip: rect(0, @radiusOuter / 2, @radiusOuter, 0);
   }
+
   .right {
     border-radius: 50%;
     background: @pcolor;
     clip: rect(0, @radiusOuter, @radiusOuter, @radiusOuter / 2);
   }
+
   .circle {
     width: @radiusInner;
     height: @radiusInner;
     border-radius: 50%;
   }
+
   * {
     position: absolute;
     left: 0;

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

@@ -14,7 +14,6 @@ const config = {
     projectNum: browser.urlQueryValue('id'),
     sceneNum: browser.urlQueryValue('vr'),
     hengdaNum: browser.urlQueryValue('h') || '6017118343179540233',
-    intranet: process.env.VUE_APP_INNERNET,
     CDN: process.env.VUE_APP_CDN,
     panoSetting:{
       angle_of_view:{

+ 102 - 80
packages/qjkankan-editor/src/core/utils.js

@@ -4,35 +4,35 @@ import Vue from 'vue'
 let vue = new Vue()
 
 export default class Utils {
-  constructor(){
-    
+  constructor() {
+
   }
   /**
    * 设置初始视角
    */
-  setInitView(krpano,canvas) {
-      let url = this.setInitAngleImg(canvas);
-      var sceneName = krpano.get('xml.scene');
-      var hlookat = krpano.get("view.hlookat");
-      var vlookat = krpano.get("view.vlookat");
-      console.log(hlookat,vlookat);
-      return {
-        sceneName,
-        hlookat,
-        vlookat,
-        url
-      }
+  setInitView(krpano, canvas) {
+    let url = this.setInitAngleImg(canvas);
+    var sceneName = krpano.get('xml.scene');
+    var hlookat = krpano.get("view.hlookat");
+    var vlookat = krpano.get("view.vlookat");
+    console.log(hlookat, vlookat);
+    return {
+      sceneName,
+      hlookat,
+      vlookat,
+      url
+    }
   }
 
-  scaleCanvas (canvas, width, height) {
+  scaleCanvas(canvas, width, height) {
     let w = canvas.width
     let h = canvas.height;
-    
+
     if (width == undefined) {
-        width = w;
+      width = w;
     }
     if (height == undefined) {
-        height = h;
+      height = h;
     }
     var retCanvas = document.createElement('canvas');
     var retCtx = retCanvas.getContext('2d');
@@ -41,17 +41,17 @@ export default class Utils {
     retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height);
     return retCanvas;
   }
-  
-  getDataURL (canvas, type, width, height) {
+
+  getDataURL(canvas, type, width, height) {
     let cas = this.scaleCanvas(canvas, width, height);
     return cas.toDataURL(type, 1);
   }
 
-  setInitAngleImg(mycanvas){
-      var url = this.getDataURL(mycanvas,"image/jpeg",600,400);
-      return url
+  setInitAngleImg(mycanvas) {
+    var url = this.getDataURL(mycanvas, "image/jpeg", 600, 400);
+    return url
   }
-  radarRotate(){
+  radarRotate() {
     // console.log(sceneName,hlookat);
   }
 
@@ -59,7 +59,7 @@ export default class Utils {
    * 编辑热点
    */
 
-  edithotspot(krpano,param){
+  edithotspot(krpano, param) {
     krpano.call(`editImgTextHotSpot(
       ${param.img},
       ${param.name},
@@ -71,57 +71,80 @@ export default class Utils {
       ${param.link},
       ${true},
       ${param.visible},
-      ${param.size||1},
-      ${param.fontSize})`); 
-   }
+      ${param.size || 1},
+      ${param.fontSize})`);
+  }
 
 
   /**
    * 添加热点
    */
 
-  addhotspot(krpano,param, type){
-    krpano.set("curscreen_x", $('#pano').width() / 2);
-    krpano.set("curscreen_y", $('#pano').height() / 2);
+  addhotspot(krpano, param, type) {
+    krpano.set("curscreen_x", krpano.get('stagewidth') / 2);
+    krpano.set("curscreen_y", krpano.get('stageheight') / 2);
     krpano.call("screentosphere(curscreen_x, curscreen_y, curscreen_ath, curscreen_atv);");
     let ath = krpano.get("curscreen_ath");
     let atv = krpano.get("curscreen_atv");
+    console.log(param.hotspotTitle,'param.hotspotTitle');
+    console.log(param.name,'param.name');
     krpano.call(`addImgTextHotSpot(
       ${param.img},
       ${param.name},
       ${param.hotspotTitle},
-      ${param.ath!=''?param.ath:ath},
-      ${param.atv!=''?param.atv:atv},
+      ${param.ath != '' ? param.ath : ath},
+      ${param.atv != '' ? param.atv : atv},
       ${true},
       ${type},
       ${param.link},
       ${true},
       ${param.visible},
       ${(param.size * 50) || 1},
-      ${Number(param.fontSize)})`); 
-
-
-      // 设置热点图片默认的偏移值
-      let offset = '-130%'
-      if (param.size < 1) {
-        offset = '-200%'
-      }
-      if (param.size > 1) {
-        offset = '-100%'
-      }
-      krpano.set('layer[tooltip_'+param.name+'].y',`${offset}`)
-      
+      ${Number(param.fontSize)})`);
+
+
+    // 设置热点图片默认的偏移值
+    let offset = '-130%'
+    if (param.size < 1) {
+      offset = '-200%'
+    }
+    if (param.size > 1) {
+      offset = '-100%'
+    }
+    krpano.set('layer[tooltip_' + param.name + '].y', `${offset}`)
+
+  }
+
+  /**
+   * 获取鼠标当前位置
+   */
+
+  getCurrentMousePosition(krpano, hotspotName) {
+    let panoW = krpano.get('stagewidth')
+    let panoH = krpano.get('stageheight')
+
+    let stagex = krpano.get('mouse.stagex')
+    let stagey = krpano.get('mouse.stagey')
+
+    if (stagex < 0 || stagex > panoW || stagey < 0 || stagey > panoH) {
+      return
+    }
+
+    krpano.call('screentosphere(mouse.stagex, mouse.stagey, toh, tov)')
+    krpano.set(`hotspot[${hotspotName}].ath`, krpano.get('toh'));
+    krpano.set(`hotspot[${hotspotName}].atv`, krpano.get('tov'));
+
   }
 
   htmlEncode(str) {
-      var s = "";
-      if (str.length == 0) return "";
-      s = str.replace(/\'/g, "&#39;");
-      s = s.replace(/\"/g, "&quot;");
-      s = s.replace(/\(/g, "(");
-      s = s.replace(/\)/g, ")");
-      s = s.replace(/,/g, ",");
-      return s;
+    var s = "";
+    if (str.length == 0) return "";
+    s = str.replace(/\'/g, "&#39;");
+    s = s.replace(/\"/g, "&quot;");
+    s = s.replace(/\(/g, "(");
+    s = s.replace(/\)/g, ")");
+    s = s.replace(/,/g, ",");
+    return s;
   }
 
   /**
@@ -129,9 +152,9 @@ export default class Utils {
    * @param {*} 定位热点 
    */
 
-  looktohotspot(krpano, hotspotName){
-      var curFov = krpano.get('view.fov');
-      krpano.call('looktohotspot('+hotspotName+','+curFov+')');
+  looktohotspot(krpano, hotspotName) {
+    var curFov = krpano.get('view.fov');
+    krpano.call('looktohotspot(' + hotspotName + ',' + curFov + ')');
   }
 
 
@@ -140,50 +163,49 @@ export default class Utils {
    * @param {*} 定位热点 
    */
 
-  getHotspotHV(krpano, hotspotName){
-      var ath = krpano.get(`hotspot[${hotspotName}].ath`);
-      var atv = krpano.get(`hotspot[${hotspotName}].atv`);
-      return {ath,atv}
+  getHotspotHV(krpano, hotspotName) {
+    var ath = krpano.get(`hotspot[${hotspotName}].ath`);
+    var atv = krpano.get(`hotspot[${hotspotName}].atv`);
+    return { ath, atv }
   }
 
-    
+
   /**
    * 打开热点链接
    */
 
-  linkopen(sceneCode,id){
-
-    if (window.location.pathname.indexOf('show')>-1) {
-      vue.$bus.emit('clickHotspot',id)
+  linkopen(sceneCode, id) {
+    if (window.location.pathname.indexOf('show') > -1) {
+      vue.$bus.emit('clickHotspot', id)
     }
-    else if (window.location.pathname.indexOf('edit')>-1) {
-      vue.$bus.emit('openHotspot',id)
+    else if (window.location.pathname.indexOf('edit') > -1) {
+      vue.$bus.emit('openHotspot', id)
     }
-    else{
-      window.parent.postMessage({ event: 'hotspot', targetCode: sceneCode },'*')
+    else {
+      window.parent.postMessage({ event: 'hotspot', targetCode: sceneCode }, '*')
     }
-   
+
   }
 
-  
 
-  
-  
+
+
+
   /**
    * 初始化
    */
 
-  initHotspot(krpano,someData,type){
+  initHotspot(krpano, someData, type) {
 
     if (!someData) {
-      return 
+      return
     }
     let mysd = someData
     if (typeof someData == 'string') {
-      mysd =  JSON.parse(someData)
+      mysd = JSON.parse(someData)
     }
     mysd.hotspots.forEach(item => {
-      this.addhotspot(krpano,item,type)
+      this.addhotspot(krpano, item, type)
     });
   }
 
@@ -191,7 +213,7 @@ export default class Utils {
    * 显示隐藏热点
    */
 
-  toggleHotspot(krpano,toggle){
+  toggleHotspot(krpano, toggle) {
     try {
       krpano.call(`set_hotspot_visible(${toggle})`);
     } catch (e) {
@@ -208,7 +230,7 @@ export default class Utils {
 
 // toggleHotspot(krpano,someData,toggle){
 //   if (!someData) {
-//     return 
+//     return
 //   }
 //   let mysd = JSON.parse(someData)
 //   mysd.hotspots.forEach(item => {

+ 46 - 43
packages/qjkankan-editor/src/framework/EditorHead.vue

@@ -1,7 +1,7 @@
 <template>
   <header class="app-head" app-border dir-bottom>
     <a class="app-head-back" href="./material.html#/works">
-      <i class="iconfont icon-editor_return" ></i>
+      <i class="iconfont icon-editor_return"></i>
       返回我的作品
     </a>
     <span class="app-head-title">{{ info.name }}</span>
@@ -10,21 +10,11 @@
       预览
     </div>
 
-    <div
-      class="ui-button submit app-head-save"
-      @click="onSave"
-      :class="{ disable: !canLoad }"
-    >
+    <div class="ui-button submit app-head-save" @click="onSave" :class="{ disable: !canLoad }">
       <i class="iconfont iconeditor_save"></i>
       保存
     </div>
-    <preview
-      v-if="info"
-      :name="info.name"
-      :show="showPreview"
-      :ifr="`./show.html?id=${info.id}`"
-      @close="showPreview = false"
-    />
+    <preview v-if="info" :name="info.name" :show="showPreview" :ifr="`./show.html?id=${info.id}`" @close="showPreview = false" />
   </header>
 </template>
 <script>
@@ -32,7 +22,7 @@ import { saveWorks, getPanoInfo, checkLogin } from "@/api";
 import { mapGetters } from "vuex";
 // import config from '@/config'
 import preview from "@/components/preview";
-let hhhreg = /\\\\\\\\/g
+let hhhreg = /\\\\\\\\/g;
 
 export default {
   name: "app-head",
@@ -46,26 +36,24 @@ export default {
   components: { preview },
 
   mounted() {
-    this.$bus.on('canLoad',(data)=>{
-      this.canLoad = data
+    this.$bus.on("canLoad", (data) => {
+      this.canLoad = data;
       if (data) {
-        this.getInfo()
-
+        this.getInfo();
       }
-    }) 
-
-
+    });
   },
   computed: {
     ...mapGetters({
       info: "info",
       isShow: "isShow",
-      catalogTopology: 'catalogTopology',
+      catalogTopology: "catalogTopology",
+      currentScene: "scene/currentScene",
     }),
   },
   methods: {
     checkParams() {
-      if (!this.info.name && !this.info.icon && !this.info.description && this.info.scenes.length<=0) {
+      if (!this.info.name && !this.info.icon && !this.info.description && this.info.scenes.length <= 0) {
         this.$alert({
           content: "您还未创建任何内容哦",
           ok: () => {
@@ -90,13 +78,13 @@ export default {
       if (!this.checkParams()) {
         return;
       }
-      this.fixData()
-      this.info.scenes = this.info.scenes.map(item=>{
-        if (typeof item.someData == 'string') {
-          item.someData =  item.someData.replace(hhhreg,'')
+      this.fixData();
+      this.info.scenes = this.info.scenes.map((item) => {
+        if (typeof item.someData == "string") {
+          item.someData = item.someData.replace(hhhreg, "");
         }
-        return item
-      })
+        return item;
+      });
 
       saveWorks(
         {
@@ -105,7 +93,7 @@ export default {
         },
         () => {
           this.$msg.success("保存成功");
-          document.title = this.info.name
+          document.title = this.info.name;
           this.getInfo();
           this.$store.commit("UpdateIsShowState", true);
           setTimeout(() => {
@@ -123,11 +111,11 @@ export default {
     fixData() {
       // 如果没有设置作品封面,拿第一个一级分组内第一个二级分组内第一个场景作为作品封面。
       if (!this.info.icon) {
-        this.info.icon = this.catalogTopology[0].children[0].children[0].icon
+        this.info.icon = this.catalogTopology[0].children[0].children[0].icon;
       }
 
       if (this.info.firstScene) {
-        this.info.firstScene = this.info.scenes.find(item=>item.sceneCode==this.info.firstScene.sceneCode)
+        this.info.firstScene = this.info.scenes.find((item) => item.sceneCode == this.info.firstScene.sceneCode);
       }
     },
 
@@ -137,13 +125,12 @@ export default {
       }
       this.fixData();
 
-
-      this.info.scenes = this.info.scenes.map(item=>{
-        if (typeof item.someData == 'string') {
-          item.someData =  item.someData.replace(hhhreg,'')
+      this.info.scenes = this.info.scenes.map((item) => {
+        if (typeof item.someData == "string") {
+          item.someData = item.someData.replace(hhhreg, "");
         }
-        return item
-      })
+        return item;
+      });
 
       saveWorks(
         {
@@ -151,8 +138,8 @@ export default {
           someData: { ...this.info, status: 1 },
         },
         () => {
-          this.$msg.success("保存成功")
-          document.title = this.info.name
+          this.$msg.success("保存成功");
+          document.title = this.info.name;
           this.getInfo();
           this.$store.commit("UpdateIsShowState", true);
         },
@@ -164,9 +151,25 @@ export default {
         if (res.code == 0) {
           getPanoInfo("", (data) => {
             this.$store.commit("SetInfo", data);
-            document.title = this.info.name || '无标题'
-          });
+            this.$store.commit("scene/setScenes", data.scenes);
 
+            let firstScene = "";
+
+            if (data.firstScene) {
+              firstScene = data.scenes.find((item) => item.sceneCode == data.firstScene.sceneCode);
+            }
+            this.$store.commit("scene/setCurrentScene", firstScene || data.scenes[0]);
+
+            // 查询初始场景的所在1级分组
+            let catalog = data.catalogs.find((item) => item.id == this.currentScene.category);
+            data.catalogRoot.forEach((item) => {
+              let temp = item.children && item.children.find((sub) => sub == catalog.id);
+              if (temp) {
+                this.$store.commit("scene/setCurrentCatalogRoot", item);
+                return;
+              }
+            });
+          });
         }
       });
     },
@@ -216,7 +219,7 @@ export default {
   }
 }
 
-.ui-preview{
+.ui-preview {
   background: #313131;
 }
 

+ 14 - 3
packages/qjkankan-editor/src/framework/play/index.vue

@@ -2,19 +2,23 @@
   <div
     class="app-player"
     ref="layer"
-    v-show="$route.meta.hasPreviewArea"
+    :class="{showPlayer:$route.meta.hasPreviewArea}"
     :style="{
       left: $route.meta.previewAreaExtraLeft + 58 + 'px',
     }"
   >
-    <iframe :src="`show.html?isEdit=1&id=${number}`" frameborder="0"></iframe>
+    <pano />
   </div>
 </template>
 
 <script>
 import config from "@/config";
+import pano from "./pano";
 
 export default {
+  components:{
+    pano
+  },
   data() {
     return {
       number: config.projectNum,
@@ -30,10 +34,17 @@ export default {
   height: 100%;
   left: 58px;
   right: 274px;
-  z-index: 999;
+  z-index: -100;
+  opacity: 0;
+  pointer-events: none;
   > iframe {
     width: 100%;
     height: 100%;
   }
+  &.showPlayer{
+    opacity: 1;
+    z-index: 999;
+    pointer-events: auto;
+  }
 }
 </style>

+ 323 - 0
packages/qjkankan-editor/src/framework/play/pano/components/list.vue

@@ -0,0 +1,323 @@
+<template>
+  <div class="bar-list" v-if="show" :class="{ disable: isEditing }">
+    <div class="top-con">
+      <div class="swiper-container" id="swScenes" v-if="currentScenesList.length > 0">
+        <ul class="swiper-wrapper">
+          <li v-tooltip="item.type==='4dkk'?'请前往四维看看个人中心编辑场景':''" @click="tabCurrentScene(item)" class="swiper-slide"
+            :class="{
+              active: currentScene.id == item.id,
+              loopspan: item.sceneTitle.length > spanlength && currentScene.id == item.id,
+            }" :style="{ backgroundImage: `url(${item.icon})`, opacity:item.type==='4dkk'?0.5:1,}"
+            v-for="(item, i) in currentScenesList" :key="i">
+            <i class="iconfont icon-edit_type_3d" :class="{ iconedit_type_panorama: item.type !== '4dkk' }"></i>
+            <div>
+              <span>{{ item.sceneTitle.length > spanlength ? item.sceneTitle.slice(0, spanlength) : item.sceneTitle
+              }}</span>
+            </div>
+          </li>
+        </ul>
+      </div>
+
+      <div class="swiper-container" id="swSecondary" v-if="secondaryList.length > 1">
+        <ul class="swiper-wrapper">
+          <li class="swiper-slide" @click="tabSecondary(item)" :class="{
+            active: currentSecondary.id == item.id,
+            loopspan: item.name.length > spanlength && currentSecondary.id == item.id,
+          }" v-for="(item, i) in secondaryList" :key="i">
+            <span>{{ item.name.length > spanlength ? item.name.slice(0, spanlength) : item.name }}</span>
+          </li>
+        </ul>
+      </div>
+    </div>
+
+    <div class="swiper-container" id="swcatalogRoot"
+      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: item.name.length > spanlength && currentCatalogRoot.id == item.id,
+        }" @click="tabRoot(item)" v-for="(item, i) in metadata.catalogRoot" :key="i">
+          <span>{{ item.name.length > spanlength ? item.name.slice(0, spanlength) : item.name }}</span>
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from "vuex";
+
+export default {
+  data() {
+    return {
+      spanlength: 6,
+      show: false,
+    };
+  },
+  watch: {
+    currentSecondary() {
+      this.loadList();
+    },
+    currentScenesList() {
+      this.loadList();
+    },
+    metadata: {
+      deep: true,
+      handler: function (newVal) {
+        if (newVal.scenes) {
+          if (!this.show) {
+            this.show = true;
+            this.loadList();
+          } else {
+            // 更新列表
+            this.tabRoot(this.currentCatalogRoot);
+          }
+        }
+      },
+    },
+  },
+  computed: {
+    ...mapGetters({
+      metadata: "scene/metadata",
+      scenes: "scene/list",
+      currentScene: "scene/currentScene",
+      currentCatalogRoot: "scene/currentCatalogRoot",
+      currentSecondary: "scene/currentSecondary",
+      secondaryList: "scene/secondaryList",
+      isShowScenesList: "scene/isShowScenesList",
+      currentScenesList: "scene/currentScenesList",
+      isEditing: "isEditing",
+    }),
+  },
+  methods: {
+    loadList() {
+      this.$nextTick(() => {
+        let t = setTimeout(() => {
+          clearTimeout(t);
+          ["#swcatalogRoot", "#swSecondary", "#swScenes"].forEach((item) => {
+            new Swiper(item, {
+              slidesPerView: "auto",
+              centeredSlides: true,
+              spaceBetween: 10,
+              centerInsufficientSlides: true,
+              centeredSlidesBounds: true,
+              freeMode: true,
+            });
+          });
+        }, 100);
+      });
+    },
+
+    tabCurrentScene(data) {
+      if (data.type !== '4dkk') {
+        this.$store.commit("scene/setCurrentScene", data);
+      }
+
+    },
+
+    tabSecondary(data) {
+      this.$store.commit("scene/setCurrentSecondary", data);
+    },
+
+    tabRoot(data) {
+      this.$store.commit("scene/setCurrentCatalogRoot", data);
+    },
+  },
+
+  mounted() {
+    // console.log(this.metadata,'metadata');
+    // this.loadList();
+  },
+};
+</script>
+
+<style lang="less" scoped>
+@width: 1150px;
+
+.bar-list {
+  position: absolute;
+  bottom: 28px;
+  left: 50%;
+  transform: translateX(-50%);
+  text-align: center;
+  max-width: @width;
+  overflow: hidden;
+  transition: 0.3s all ease;
+
+  .swiper-container {
+    width: 100%;
+    position: relative;
+
+    >ul {
+      >li {
+
+        >span,
+        >div>span {
+          cursor: pointer;
+          display: inline-block;
+          color: rgba(255, 255, 255, 0.6);
+        }
+
+        &.loopspan {
+
+          >span,
+          >div>span {
+            animation: 5s wordsLoop linear infinite normal;
+          }
+        }
+
+        &.active {
+
+          >span,
+          >div>span {
+            color: rgba(255, 255, 255, 1);
+          }
+        }
+      }
+    }
+  }
+
+  .top-con {
+    margin-bottom: 10px;
+    padding: 10px 30px;
+    min-width: 400px;
+    background: linear-gradient(268deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.5) 8%, rgba(0, 0, 0, 0.5) 92%, 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: @color;
+          }
+        }
+      }
+    }
+  }
+
+  #swScenes {
+    margin: 0 auto;
+
+    >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 {
+            width: 100%;
+            line-height: 20px;
+            word-break: keep-all;
+          }
+        }
+
+        &.active {
+          border: 1px solid @color;
+
+          >div {
+            >span {}
+          }
+        }
+      }
+    }
+  }
+}
+
+.barshow {
+  max-height: 520px;
+}
+
+@keyframes wordsLoop {
+  0% {
+    transform: translateX(100%);
+    -webkit-transform: translateX(100%);
+  }
+
+  100% {
+    transform: translateX(-100%);
+    -webkit-transform: translateX(-100%);
+  }
+}
+</style>

+ 178 - 0
packages/qjkankan-editor/src/framework/play/pano/index.vue

@@ -0,0 +1,178 @@
+<template>
+  <div class="panocon">
+    <div id="pano"></div>
+    <list></list>
+
+    <template v-if="showSnapshot&&currentScene">
+      <snapshot :showFlash="showFlash"></snapshot>
+      <button class="ui-button submit" @click="onClick">将当前视角设为初始画面</button>
+    </template>
+  </div>
+</template>
+
+<script>
+import list from "./components/list";
+import { mapGetters } from "vuex";
+import * as krfn from "@/core/index.js";
+import { $waiting } from "@/components/shared/loading";
+import Snapshot from "@/components/Snapshot";
+import { uploadCover } from "@/api";
+
+
+let __krfn = krfn.default;
+
+export default {
+  components: { list, Snapshot },
+  data() {
+    return {
+      showFlash: false,
+      inter: null
+    }
+  },
+  computed: {
+    ...mapGetters({
+      currentScene: "scene/currentScene",
+      info: "info",
+      isConfirmingPosi: "tags/isConfirmingPosi",
+    }),
+
+    showSnapshot() {
+      return this.$route.name == "screen";
+    },
+  },
+  watch: {
+    '$route.name': function (newVal) {
+      __krfn.utils.toggleHotspot(this.$getKrpano(), newVal == 'hotspot');
+    },
+    currentScene(newVal) {
+      if (newVal) {
+        this.$nextTick(() => {
+          this.$bus.emit("initView", newVal.icon);
+        })
+      }
+
+      $("#pano").empty();
+      window.vrInitFn = () => {
+        $waiting.hide()
+        __krfn.utils.initHotspot(this.$getKrpano(), newVal && newVal.someData, true);
+        __krfn.utils.toggleHotspot(this.$getKrpano(), this.$route.name == "hotspot");
+      };
+      window.vrViewFn = () => {
+        try {
+          let tmp = newVal.initVisual;
+          this.$getKrpano().set("view.vlookat", tmp.vlookat);
+          this.$getKrpano().set("view.hlookat", tmp.hlookat);
+        } catch (error) {
+          error;
+        }
+      };
+
+      var settings = {
+        "events[skin_events].onxmlcomplete": "js(window.vrViewFn());",
+        "events[skin_events].onloadcomplete": "js(window.vrInitFn());",
+      };
+
+      if (newVal) {
+        removepano("#pano");
+        $waiting.show();
+        embedpano({
+          // http://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/720yun_fd_manage/fd720_Va0LrkXW3/vtour/tour.xml
+          // xml: "%HTMLPATH%/static/template/tour.xml",
+          xml: `${this.$cdn}/720yun_fd_manage/${newVal.sceneCode}/vtour/tour.xml`,
+          swf: "%HTMLPATH%/static/template/tour.swf",
+          target: "pano",
+          html5: "auto",
+          mobilescale: 1,
+          vars: settings,
+          webglsettings: { preserveDrawingBuffer: true },
+          passQueryParameters: true,
+        });
+      }
+    },
+    isConfirmingPosi(newVal) {
+      this.inter && clearInterval(this.inter)
+      this.inter = null
+      if (newVal) {
+        this.inter = setInterval(() => {
+          __krfn.utils.getCurrentMousePosition(this.$getKrpano(), newVal)
+        }, 20);
+      }
+    }
+
+  },
+  methods: {
+    updateInfo() {
+      let iidx = this.info.scenes.findIndex(item => this.currentScene.sceneCode == item.sceneCode)
+      if (iidx > -1) {
+        this.info.scenes[iidx] = {
+          ...this.currentScene
+        }
+      }
+      this.$store.commit("SetInfo", this.info);
+    },
+    onClick() {
+      this.$bus.emit('toggleFlash', true)
+      let canvas = $("#krpanoSWFObject canvas")[0];
+      let data = __krfn.utils.setInitView(this.$getKrpano(), canvas);
+      uploadCover(
+        { file: data.url, filename: "initCover.jpg" },
+        res => {
+          if (res.code == 0) {
+            this.currentScene.icon = res.data
+            this.currentScene.initVisual = {
+              hlookat: data.hlookat,
+              vlookat: data.vlookat
+            }
+            this.$bus.emit('toggleFlash', false)
+            this.$bus.emit("initView", res.data);
+            this.updateInfo()
+            this.$msg.success("设置成功")
+            this.$store.commit("SetInfo", this.info);
+          }
+        });
+    },
+
+    addhotspot(param) {
+      __krfn.utils.addhotspot(this.$getKrpano(), param, true);
+      this.$store.commit("tags/setIsConfirmingPosi", param.name);
+
+    }
+
+  },
+  mounted() {
+    window.__krfn = __krfn;
+
+    this.$bus.on("addhotspot", data => {
+      this.addhotspot(data);
+    });
+
+    this.$bus.on("openHotspot", (data) => {
+      if (this.isConfirmingPosi) {
+        this.$store.commit("tags/setIsConfirmingPosi", false);
+      }
+    })
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.panocon {
+  width: 100%;
+  height: 100%;
+  position: relative;
+
+  #pano {
+    width: 100%;
+    height: 100%;
+  }
+
+  .ui-button {
+    position: absolute;
+    bottom: 260px;
+    min-width: 200px;
+    left: 50%;
+    transform: translateX(-50%);
+    z-index: 99;
+  }
+}
+</style>

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

@@ -39,7 +39,6 @@ Vue.use(InfiniteScroll)
 
 Vue.prototype.$bus = bus;
 Vue.prototype.$api = api;
-Vue.prototype.$intranet = config.intranet;
 Vue.prototype.$cdn = config.CDN;
 Vue.prototype.$config = config;
 Vue.prototype.$thumb = config.thumb;

+ 30 - 21
packages/qjkankan-editor/src/views/explanation/explanationSettings.vue

@@ -4,14 +4,14 @@
       语音讲解
       <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="'您可以为当前全景图添加语音讲解音频。'"/>
     </div>
-    <button v-if="!info.explanation.audioId" class="ui-button submit" @click="isShowSelectionWindow = true">
+    <button v-if="!currentScene.explanation.audioId" class="ui-button submit" @click="isShowSelectionWindow = true">
       <i class="iconfont icon-editor_add"></i>
       添加音频
     </button>
     <template v-else>
       <div class="music-display" @click.self="onClickCurrentMusic">
-        <Audio ref="my-audio" class="audio-control" :backgroundColor="'#1A1B1D'" :myAudioUrl="info.explanation.audioUrl"></Audio>
-        <div class="name" v-title="info.explanation.audioName" @click="onClickCurrentMusic">{{info.explanation.audioName}}</div>
+        <Audio ref="my-audio" class="audio-control" :backgroundColor="'#1A1B1D'" :myAudioUrl="currentScene.explanation.audioUrl"></Audio>
+        <div class="name" :key="currentScene.explanation.audioName" v-title="currentScene.explanation.audioName" @click="onClickCurrentMusic">{{currentScene.explanation.audioName}}</div>
         <i class="iconfont icon-editor_list_delete" @click.stop="onClickDeleteMusicBtn"></i>
       </div>
       <button class="ui-button" @click="isShowSelectionWindow = true">
@@ -22,11 +22,11 @@
 
     <div class="switch-wrapper">
       <span class="label">默认开启</span>
-      <Switcher :value="info.explanation.openByDefault" @change="info.explanation.openByDefault = !info.explanation.openByDefault"></Switcher>
+      <Switcher :value="currentScene.explanation.openByDefault" @change="currentScene.explanation.openByDefault = !currentScene.explanation.openByDefault"></Switcher>
     </div>
     <div class="switch-wrapper">
       <span class="label">循环播放</span>
-      <Switcher :value="info.explanation.repeat" @change="info.explanation.repeat = !info.explanation.repeat"></Switcher>
+      <Switcher :value="currentScene.explanation.repeat" @change="currentScene.explanation.repeat = !currentScene.explanation.repeat"></Switcher>
     </div>
 
     <div class="dialog" style="z-index: 2000" v-if="isShowSelectionWindow">
@@ -56,6 +56,7 @@ export default {
   computed: {
     ...mapGetters({
         info: "info",
+        currentScene: "scene/currentScene",
     }),
   },
   data() {
@@ -65,32 +66,40 @@ export default {
   },
   methods: {
     onClickCurrentMusic() {
+      console.log(this.$refs['my-audio']);
       if (this.$refs['my-audio']) {
         this.$refs['my-audio'].switchPlayPause()
       }
     },
     onClickDeleteMusicBtn() {
-      this.info.explanation.audioId = ''
-      this.info.explanation.audioUrl = ''
-      this.info.explanation.audioName = ''
+      this.currentScene.explanation.audioId = ''
+      this.currentScene.explanation.audioUrl = ''
+      this.currentScene.explanation.audioName = ''
     },
     handleSubmitFromMaterialSelector(selected) {
+      console.log(selected);
+      this.currentScene.explanation.audioId = selected[0].id
+      this.currentScene.explanation.audioName = selected[0].name
+      this.currentScene.explanation.audioUrl = selected[0].ossPath
       this.isShowSelectionWindow = false
-      this.info.explanation.audioId = selected[0].id
-      this.info.explanation.audioName = selected[0].name
-      this.info.explanation.audioOssPath = selected[0].ossPath
+
     },
   },
-  created() {
-    if (!this.info.explanation) {
-      this.$set(this.info, 'explanation', {
-        audioId: '',
-        audioName: '',
-        audioUrl: '',
-        openByDefault: true,
-        repeat: true,
-      })
-    }
+  watch: {
+    currentScene: {
+      immediate: true,
+      handler: function (newVal) {
+        if (!newVal.explanation) {
+          this.$set(newVal, 'explanation', {
+            audioId: '',
+            audioName: '',
+            audioUrl: '',
+            openByDefault: true,
+            repeat: true,
+          })
+        }
+      },
+    },
   },
 }
 </script>

+ 9 - 17
packages/qjkankan-editor/src/views/hotspot/EditPanel.vue

@@ -193,24 +193,21 @@ export default {
 
   watch:{
     'hotspot.hotspotTitle':function () {
-      let krpano = document.getElementById('krpanoSWFObject');
-      krpano.set('layer[tooltip_'+this.hotspot.name+'].html',this.hotspot.hotspotTitle)
+      this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].html',this.hotspot.hotspotTitle)
     },
     'hotspot.visible':function () {
-      let krpano = document.getElementById('krpanoSWFObject');
-      krpano.set('layer[tooltip_'+this.hotspot.name+'].visible',this.hotspot.visible)
+      this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].visible',this.hotspot.visible)
     },
     'hotspot.size': {
       immediate:true,
       handler:function (newVal) {
-        let krpano = document.getElementById('krpanoSWFObject');
         let h = 52
         let scaleH = h*newVal
 
         let offset = '-130%'
 
         this.rang = { ...this.rang, value: newVal }
-        krpano.set(`hotspot[${this.hotspot.name}].height`,scaleH)
+        this.$getKrpano().set(`hotspot[${this.hotspot.name}].height`,scaleH)
         
         if (newVal < 1) {
           offset = '-200%'
@@ -219,15 +216,14 @@ export default {
         if (newVal > 1) {
           offset = '-100%'
         }
-        krpano.set('layer[tooltip_'+this.hotspot.name+'].y',`${offset}`)
+        this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].y',`${offset}`)
 
 
       }
     },
     'hotspot.fontSize':{
       handler:function (newVal) {
-        let krpano = document.getElementById('krpanoSWFObject');
-        krpano.set('layer[tooltip_'+this.hotspot.name+'].css',`text-align:center; color:#FFFFFF;
+        this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].css',`text-align:center; color:#FFFFFF;
           font-family:STXihei;font-size:${newVal}px;`)
       }
     },
@@ -321,8 +317,7 @@ export default {
     reset(data){
       this.$bus.emit('edithotspotTitle',data)
       this.$bus.emit('edithotspotTitleisShow',data)
-      let krpano = document.getElementById('krpanoSWFObject');
-      krpano.set(`hotspot[${data.name}].url`,data.img)
+      this.$getKrpano().set(`hotspot[${data.name}].url`,data.img)
     },
     save() {
       let {img,hotspotTitle,hotspotType} = this.hotspot
@@ -350,7 +345,6 @@ export default {
       this.$emit("save",this.hotspot);
     },
     addhotspot(data){
-      let krpano = document.getElementById('krpanoSWFObject');
 
       if (this.isAdd) {
         this.isAdd = false
@@ -358,17 +352,15 @@ export default {
         this.hotspot.icontype = data.id
         this.styIcon = data.id
         this.$bus.emit('addhotspot',this.hotspot)
-        krpano.set('layer[tooltip_'+this.hotspot.name+'].css',`text-align:center; color:#FFFFFF;
+        this.$getKrpano().set('layer[tooltip_'+this.hotspot.name+'].css',`text-align:center; color:#FFFFFF;
           font-family:STXihei;font-size:${this.hotspot.fontSize}px;`)
       }
       else{
         this.hotspot.img = data.img
         this.hotspot.icontype = data.id
         this.styIcon = data.id
-        krpano.set(`hotspot[${this.hotspot.name}].url`,data.img)
-        krpano.set(`hotspot[${this.hotspot.name}].hotspottitle`,this.hotspot.hotspotTitle)
-        
-
+        this.$getKrpano().set(`hotspot[${this.hotspot.name}].url`,data.img)
+        this.$getKrpano().set(`hotspot[${this.hotspot.name}].hotspottitle`,this.hotspot.hotspotTitle)
       }
     }
   }

+ 14 - 17
packages/qjkankan-editor/src/views/hotspot/HotSpotList.vue

@@ -6,7 +6,7 @@
     </div>
     <button
       class="ui-button submit"
-      :class="{ disable: !activeItem }"
+      :class="{ disable: !currentScene }"
       @click="open(null)"
     >
       添加热点
@@ -66,7 +66,7 @@ export default {
   },
   computed: {
     ...mapGetters({
-      activeItem: "activeItem",
+      currentScene: "scene/currentScene",
       hotspot: 'hotspot',
       info: "info"
     }),
@@ -84,7 +84,7 @@ export default {
     "$route.name": function () {
       this.showPanel = false
     },
-    activeItem: {
+    currentScene: {
       immediate: true,
       handler: function (newVal) {
         this.someData = newVal.someData || ""
@@ -109,7 +109,7 @@ export default {
     },
     showPanel(newVal) {
       this.$store.commit("UpdateIsEditingState", newVal)
-      this.$bus.emit("canEdit", !newVal)
+      this.$store.commit("tags/setIsConfirmingPosi", false);
     },
   },
   mounted() {
@@ -138,9 +138,8 @@ export default {
   },
   methods: {
     deleteKRHotspot(data) {
-      let krpano = document.getElementById("krpanoSWFObject")
-      krpano.call("removehotspot(" + data.name + ",true);")
-      krpano.call("removeplugin(" + ("tooltip_" + data.name) + ",true);")
+      this.$getKrpano().call("removehotspot(" + data.name + ",true);")
+      this.$getKrpano().call("removeplugin(" + ("tooltip_" + data.name) + ",true);")
     },
     close(data) {
       if (data) {
@@ -158,17 +157,16 @@ export default {
     },
 
     updateInfo() {
-      let iidx = this.info.scenes.findIndex(item => this.activeItem.sceneCode == item.sceneCode)
+      let iidx = this.info.scenes.findIndex(item => this.currentScene.sceneCode == item.sceneCode)
       if (iidx > -1) {
         this.info.scenes[iidx] = {
-          ...this.activeItem
+          ...this.currentScene
         }
       }
       this.$store.commit("SetInfo", this.info)
     },
     save(data) {
-      var krpano = document.getElementById("krpanoSWFObject")
-      let HV = window.__krfn.utils.getHotspotHV(krpano, data.name)
+      let HV = window.__krfn.utils.getHotspotHV(this.$getKrpano(), data.name)
       data.ath = HV.ath
       data.atv = HV.atv
       let idx = this.someData.hotspots.findIndex((item) => item.name === data.name)
@@ -179,13 +177,13 @@ export default {
         this.someData.hotspots[idx] = data
       }
 
-      this.activeItem.someData = this.someData
+      this.currentScene.someData = this.someData
       this.$msg.success(this.editTitle + "成功")
 
-      let iidx = this.info.scenes.findIndex(item => this.activeItem.sceneCode == item.sceneCode)
+      let iidx = this.info.scenes.findIndex(item => this.currentScene.sceneCode == item.sceneCode)
       if (iidx > -1) {
         this.info.scenes[iidx] = {
-          ...this.activeItem
+          ...this.currentScene
         }
       }
 
@@ -198,7 +196,7 @@ export default {
         1
       )
       this.deleteKRHotspot(data)
-      this.activeItem.someData = this.someData
+      this.currentScene.someData = this.someData
       this.updateInfo()
       this.$msg.success("删除成功")
     },
@@ -231,8 +229,7 @@ export default {
       if (data) {
         this.editLink = temp.link
         this.editTitle = "编辑"
-        var krpano = document.getElementById("krpanoSWFObject")
-        window.__krfn.utils.looktohotspot(krpano, data.name)
+        window.__krfn.utils.looktohotspot(this.$getKrpano(), data.name)
       }
     },
     clickoutside() {

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

@@ -32,6 +32,7 @@ export default {
   position: relative;
   .hot-spot-list {
     position: absolute;
+    z-index: 1000;
     right: 0;
     width: 274px;
     top: 0;

+ 12 - 0
packages/qjkankan-editor/src/views/screen/Setting.vue

@@ -10,7 +10,14 @@
 </template>
 
 <script>
+import { mapGetters } from "vuex";
+
 export default {
+  computed: {
+    ...mapGetters({
+      currentScene: "scene/currentScene",
+    })
+  },
   methods:{
 
   },
@@ -23,6 +30,11 @@ export default {
     this.$bus.on('initView', data => {
       this.initImg = data
     })
+
+    if (!this.initImg) {
+      this.initImg = this.currentScene.icon
+    }
+    
   }
 }
 </script>

+ 4 - 4
packages/qjkankan-kankan-view/.env

@@ -1,19 +1,19 @@
 
 # 场景资源地址
-VUE_APP_RESOURCE_URL=https://eurs3.4dkankan.com/
+VUE_APP_RESOURCE_URL=https://4dkk.4dage.com/
 # 静态资源地址
 VUE_APP_CDN_URL=https://4dkk.4dage.com/v4/www/
 # sdk文件地址
-VUE_APP_SDK_DIR=https://eurs3.4dkankan.com/v4/cdfg/sdk
+VUE_APP_SDK_DIR=https://4dkk.4dage.com/v4/www/sdk/
 
 
 # 静态资源目录
 VUE_APP_STATIC_DIR=viewer
 
 # 云存储环境
-VUE_APP_REGION_URL=aws
+VUE_APP_REGION_URL=
 
 
 # 接口请求地址
-VUE_APP_APIS_URL=http://192.168.0.38:8888/
+VUE_APP_APIS_URL=https://test.4dkankan.com/
 

+ 4 - 0
packages/qjkankan-kankan-view/.env.development

@@ -3,6 +3,10 @@
 VUE_APP_RESOURCE_URL=https://4dkk.4dage.com/
 # 静态资源地址
 VUE_APP_CDN_URL=https://4dkk.4dage.com/v4/www/
+# sdk文件地址
+VUE_APP_SDK_DIR=https://4dkk.4dage.com/v4/www/sdk/
+
+
 
 # 静态资源目录
 VUE_APP_STATIC_DIR=viewer

+ 442 - 6
packages/qjkankan-kankan-view/package-lock.json

@@ -12,9 +12,11 @@
         "clipboard": "^2.0.8",
         "core-js": "^3.8.3",
         "vue": "^3.2.36",
+        "vue-i18n": "9",
         "vuex": "^4.0.2"
       },
       "devDependencies": {
+        "@intlify/vue-i18n-loader": "^4.2.0",
         "@vue/cli-plugin-babel": "~5.0.0",
         "@vue/cli-service": "~5.0.0",
         "@vue/compiler-sfc": "^3.0.0",
@@ -1704,6 +1706,130 @@
         "@hapi/hoek": "^9.0.0"
       }
     },
+    "node_modules/@intlify/bundle-utils": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/bundle-utils/-/bundle-utils-2.2.2.tgz",
+      "integrity": "sha512-vngkvlIVV8ZJoyC5VqMvqJd2nvsx+qMN7pQjPiPjOrVndeiR7Dlue0k86Q8FsFUzyksW3HJZZi833ldxwbFzTA==",
+      "dev": true,
+      "dependencies": {
+        "@intlify/message-compiler": "^9.1.0",
+        "@intlify/shared": "^9.1.0",
+        "jsonc-eslint-parser": "^1.0.1",
+        "source-map": "^0.6.1",
+        "yaml-eslint-parser": "^0.3.2"
+      },
+      "engines": {
+        "node": ">= 12"
+      },
+      "peerDependenciesMeta": {
+        "petite-vue-i18n": {
+          "optional": true
+        },
+        "vue-i18n": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@intlify/core-base": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.2.2.tgz",
+      "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
+      "dependencies": {
+        "@intlify/devtools-if": "9.2.2",
+        "@intlify/message-compiler": "9.2.2",
+        "@intlify/shared": "9.2.2",
+        "@intlify/vue-devtools": "9.2.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@intlify/devtools-if": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
+      "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
+      "dependencies": {
+        "@intlify/shared": "9.2.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@intlify/message-compiler": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
+      "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
+      "dependencies": {
+        "@intlify/shared": "9.2.2",
+        "source-map": "0.6.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@intlify/shared": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.2.2.tgz",
+      "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@intlify/vue-devtools": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
+      "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
+      "dependencies": {
+        "@intlify/core-base": "9.2.2",
+        "@intlify/shared": "9.2.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/@intlify/vue-i18n-loader": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmmirror.com/@intlify/vue-i18n-loader/-/vue-i18n-loader-4.2.0.tgz",
+      "integrity": "sha512-d7aBmMNWJskcZPT5rJH4h2XHe/PwNoJUaY0PGla9g+NSD4B0UR8LBKrp126nlaUfA74Xt0FEGvzCfG9KdC9KoA==",
+      "dev": true,
+      "dependencies": {
+        "@intlify/bundle-utils": "^2.2.2",
+        "@intlify/shared": "^9.1.0",
+        "js-yaml": "^4.1.0",
+        "json5": "^2.2.0",
+        "loader-utils": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 12"
+      },
+      "peerDependencies": {
+        "petite-vue-i18n": "^9.1.0",
+        "vue": "^3.0.0",
+        "vue-i18n": "^9.1.0"
+      },
+      "peerDependenciesMeta": {
+        "petite-vue-i18n": {
+          "optional": true
+        },
+        "vue-i18n": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@intlify/vue-i18n-loader/node_modules/loader-utils": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.2.tgz",
+      "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
+      "dev": true,
+      "dependencies": {
+        "big.js": "^5.2.2",
+        "emojis-list": "^3.0.0",
+        "json5": "^2.1.2"
+      },
+      "engines": {
+        "node": ">=8.9.0"
+      }
+    },
     "node_modules/@jridgewell/gen-mapping": {
       "version": "0.1.1",
       "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
@@ -2702,9 +2828,9 @@
       "dev": true
     },
     "node_modules/@vue/devtools-api": {
-      "version": "6.1.4",
-      "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.1.4.tgz",
-      "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ=="
+      "version": "6.2.1",
+      "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.2.1.tgz",
+      "integrity": "sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ=="
     },
     "node_modules/@vue/reactivity": {
       "version": "3.2.36",
@@ -2992,6 +3118,15 @@
         "acorn": "^8"
       }
     },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
     "node_modules/acorn-walk": {
       "version": "8.2.0",
       "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.2.0.tgz",
@@ -3133,6 +3268,12 @@
       "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
       "dev": true
     },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
     "node_modules/array-flatten": {
       "version": "2.1.2",
       "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-2.1.2.tgz",
@@ -4756,6 +4897,53 @@
         "node": ">=8.0.0"
       }
     },
+    "node_modules/eslint-utils": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-2.1.0.tgz",
+      "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+      "dev": true,
+      "dependencies": {
+        "eslint-visitor-keys": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+      "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/espree": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmmirror.com/espree/-/espree-6.2.1.tgz",
+      "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^7.1.1",
+        "acorn-jsx": "^5.2.0",
+        "eslint-visitor-keys": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/espree/node_modules/acorn": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz",
+      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/esrecurse": {
       "version": "4.3.0",
       "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -5853,6 +6041,18 @@
       "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
       "dev": true
     },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
     "node_modules/jsesc": {
       "version": "2.5.2",
       "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-2.5.2.tgz",
@@ -5895,6 +6095,34 @@
         "node": ">=6"
       }
     },
+    "node_modules/jsonc-eslint-parser": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmmirror.com/jsonc-eslint-parser/-/jsonc-eslint-parser-1.4.1.tgz",
+      "integrity": "sha512-hXBrvsR1rdjmB2kQmUjf1rEIa+TqHBGMge8pwi++C+Si1ad7EjZrJcpgwym+QGK/pqTx+K7keFAtLlVNdLRJOg==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^7.4.1",
+        "eslint-utils": "^2.1.0",
+        "eslint-visitor-keys": "^1.3.0",
+        "espree": "^6.0.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/jsonc-eslint-parser/node_modules/acorn": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz",
+      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/jsonfile": {
       "version": "6.1.0",
       "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -9086,6 +9314,23 @@
       "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
       "dev": true
     },
+    "node_modules/vue-i18n": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.2.2.tgz",
+      "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
+      "dependencies": {
+        "@intlify/core-base": "9.2.2",
+        "@intlify/shared": "9.2.2",
+        "@intlify/vue-devtools": "9.2.2",
+        "@vue/devtools-api": "^6.2.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
     "node_modules/vue-loader": {
       "version": "17.0.0",
       "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-17.0.0.tgz",
@@ -9774,6 +10019,17 @@
         "node": ">= 6"
       }
     },
+    "node_modules/yaml-eslint-parser": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmmirror.com/yaml-eslint-parser/-/yaml-eslint-parser-0.3.2.tgz",
+      "integrity": "sha512-32kYO6kJUuZzqte82t4M/gB6/+11WAuHiEnK7FreMo20xsCKPeFH5tDBU7iWxR7zeJpNnMXfJyXwne48D0hGrg==",
+      "dev": true,
+      "dependencies": {
+        "eslint-visitor-keys": "^1.3.0",
+        "lodash": "^4.17.20",
+        "yaml": "^1.10.0"
+      }
+    },
     "node_modules/yargs": {
       "version": "16.2.0",
       "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz",
@@ -10980,6 +11236,87 @@
         "@hapi/hoek": "^9.0.0"
       }
     },
+    "@intlify/bundle-utils": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/bundle-utils/-/bundle-utils-2.2.2.tgz",
+      "integrity": "sha512-vngkvlIVV8ZJoyC5VqMvqJd2nvsx+qMN7pQjPiPjOrVndeiR7Dlue0k86Q8FsFUzyksW3HJZZi833ldxwbFzTA==",
+      "dev": true,
+      "requires": {
+        "@intlify/message-compiler": "^9.1.0",
+        "@intlify/shared": "^9.1.0",
+        "jsonc-eslint-parser": "^1.0.1",
+        "source-map": "^0.6.1",
+        "yaml-eslint-parser": "^0.3.2"
+      }
+    },
+    "@intlify/core-base": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.2.2.tgz",
+      "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
+      "requires": {
+        "@intlify/devtools-if": "9.2.2",
+        "@intlify/message-compiler": "9.2.2",
+        "@intlify/shared": "9.2.2",
+        "@intlify/vue-devtools": "9.2.2"
+      }
+    },
+    "@intlify/devtools-if": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
+      "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
+      "requires": {
+        "@intlify/shared": "9.2.2"
+      }
+    },
+    "@intlify/message-compiler": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
+      "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
+      "requires": {
+        "@intlify/shared": "9.2.2",
+        "source-map": "0.6.1"
+      }
+    },
+    "@intlify/shared": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.2.2.tgz",
+      "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q=="
+    },
+    "@intlify/vue-devtools": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
+      "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
+      "requires": {
+        "@intlify/core-base": "9.2.2",
+        "@intlify/shared": "9.2.2"
+      }
+    },
+    "@intlify/vue-i18n-loader": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmmirror.com/@intlify/vue-i18n-loader/-/vue-i18n-loader-4.2.0.tgz",
+      "integrity": "sha512-d7aBmMNWJskcZPT5rJH4h2XHe/PwNoJUaY0PGla9g+NSD4B0UR8LBKrp126nlaUfA74Xt0FEGvzCfG9KdC9KoA==",
+      "dev": true,
+      "requires": {
+        "@intlify/bundle-utils": "^2.2.2",
+        "@intlify/shared": "^9.1.0",
+        "js-yaml": "^4.1.0",
+        "json5": "^2.2.0",
+        "loader-utils": "^2.0.0"
+      },
+      "dependencies": {
+        "loader-utils": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.2.tgz",
+          "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
+          "dev": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
+          }
+        }
+      }
+    },
     "@jridgewell/gen-mapping": {
       "version": "0.1.1",
       "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
@@ -11822,9 +12159,9 @@
       }
     },
     "@vue/devtools-api": {
-      "version": "6.1.4",
-      "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.1.4.tgz",
-      "integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ=="
+      "version": "6.2.1",
+      "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.2.1.tgz",
+      "integrity": "sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ=="
     },
     "@vue/reactivity": {
       "version": "3.2.36",
@@ -12087,6 +12424,13 @@
       "dev": true,
       "requires": {}
     },
+    "acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "requires": {}
+    },
     "acorn-walk": {
       "version": "8.2.0",
       "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.2.0.tgz",
@@ -12196,6 +12540,12 @@
       "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
       "dev": true
     },
+    "argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
     "array-flatten": {
       "version": "2.1.2",
       "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-2.1.2.tgz",
@@ -13507,6 +13857,40 @@
         "estraverse": "^4.1.1"
       }
     },
+    "eslint-utils": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-2.1.0.tgz",
+      "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+      "dev": true,
+      "requires": {
+        "eslint-visitor-keys": "^1.1.0"
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+      "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+      "dev": true
+    },
+    "espree": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmmirror.com/espree/-/espree-6.2.1.tgz",
+      "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
+      "dev": true,
+      "requires": {
+        "acorn": "^7.1.1",
+        "acorn-jsx": "^5.2.0",
+        "eslint-visitor-keys": "^1.1.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "7.4.1",
+          "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz",
+          "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+          "dev": true
+        }
+      }
+    },
     "esrecurse": {
       "version": "4.3.0",
       "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -14393,6 +14777,15 @@
       "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
       "dev": true
     },
+    "js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "requires": {
+        "argparse": "^2.0.1"
+      }
+    },
     "jsesc": {
       "version": "2.5.2",
       "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-2.5.2.tgz",
@@ -14423,6 +14816,27 @@
       "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
       "dev": true
     },
+    "jsonc-eslint-parser": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmmirror.com/jsonc-eslint-parser/-/jsonc-eslint-parser-1.4.1.tgz",
+      "integrity": "sha512-hXBrvsR1rdjmB2kQmUjf1rEIa+TqHBGMge8pwi++C+Si1ad7EjZrJcpgwym+QGK/pqTx+K7keFAtLlVNdLRJOg==",
+      "dev": true,
+      "requires": {
+        "acorn": "^7.4.1",
+        "eslint-utils": "^2.1.0",
+        "eslint-visitor-keys": "^1.3.0",
+        "espree": "^6.0.0",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "7.4.1",
+          "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz",
+          "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+          "dev": true
+        }
+      }
+    },
     "jsonfile": {
       "version": "6.1.0",
       "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -16905,6 +17319,17 @@
       "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
       "dev": true
     },
+    "vue-i18n": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.2.2.tgz",
+      "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
+      "requires": {
+        "@intlify/core-base": "9.2.2",
+        "@intlify/shared": "9.2.2",
+        "@intlify/vue-devtools": "9.2.2",
+        "@vue/devtools-api": "^6.2.1"
+      }
+    },
     "vue-loader": {
       "version": "17.0.0",
       "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-17.0.0.tgz",
@@ -17449,6 +17874,17 @@
       "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
       "dev": true
     },
+    "yaml-eslint-parser": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmmirror.com/yaml-eslint-parser/-/yaml-eslint-parser-0.3.2.tgz",
+      "integrity": "sha512-32kYO6kJUuZzqte82t4M/gB6/+11WAuHiEnK7FreMo20xsCKPeFH5tDBU7iWxR7zeJpNnMXfJyXwne48D0hGrg==",
+      "dev": true,
+      "requires": {
+        "eslint-visitor-keys": "^1.3.0",
+        "lodash": "^4.17.20",
+        "yaml": "^1.10.0"
+      }
+    },
     "yargs": {
       "version": "16.2.0",
       "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz",

+ 2 - 0
packages/qjkankan-kankan-view/package.json

@@ -13,9 +13,11 @@
     "vue": "^3.2.36",
     "axios": "^0.21.1",
     "clipboard": "^2.0.8",
+    "vue-i18n": "9",
     "vuex": "^4.0.2"
   },
   "devDependencies": {
+    "@intlify/vue-i18n-loader": "^4.2.0",
     "@vue/cli-plugin-babel": "~5.0.0",
     "@vue/cli-service": "~5.0.0",
     "@vue/compiler-sfc": "^3.0.0",

+ 3 - 2
packages/qjkankan-kankan-view/public/spg.html

@@ -17,8 +17,9 @@
         </noscript>
         <div id="app"></div>
         
-        <script src="<%= BASE_URL %><%= VUE_APP_SDK_DIR %>/kankan-sdk-deps.js?v=<%= VUE_APP_VERSION %>"></script>
-        <script src="<%= BASE_URL %><%= VUE_APP_SDK_DIR %>/kankan-sdk.js?v=<%= VUE_APP_VERSION %>"></script>
+        <script src="<%= VUE_APP_CDN_URL %>sdk/kankan-sdk-deps.js?v=4.0.0-alpha.47"></script>
+        <script src="<%= VUE_APP_CDN_URL %>sdk/kankan-sdk.js?v=4.0.0-alpha.47"></script>
+
         <!-- built files will be auto injected -->
     </body>
 </html>

+ 3 - 1
packages/qjkankan-kankan-view/src/components/Information/index.vue

@@ -1,12 +1,14 @@
 <template>
     <div class="information" :class="{ mobile: mobile, disabled: isPlay }">
         <!-- <component :is="page"></component> -->
-        <ViewMobile />
+        <ViewMobile v-if="mobile" />
+        <ViewPc v-else />
     </div>
 </template>
 
 <script setup>
 import ViewMobile from './View.Mobile.vue'
+import ViewPc from './View.Pc.vue'
 import { ref, markRaw, onMounted, computed, watch } from 'vue'
 import { useApp } from '@/app'
 import { useStore } from 'vuex'

+ 427 - 313
packages/qjkankan-kankan-view/src/pages/SMG.vue

@@ -1,301 +1,304 @@
 <template>
     <Password />
-    <Guide />
     <LoadingLogo :thumb="true" />
+    <Guide />
     <div class="ui-view-layout" :class="{ show: show }" is-mobile="true">
-        <div class="scene" ref="scene$"></div>
-        <template v-if="dataLoaded">
-            <Information />
-            <Control />
-            <!-- <teleport v-if="refMiniMap && player.showWidgets" :to="refMiniMap"> -->
-            <teleport v-if="refMiniMap" :to="refMiniMap">
-                <span class="button-switch" @click.stop="toggleMap">
-                    <ui-icon type="show_map_collect"></ui-icon>
-                </span>
-                <div v-if="controls.showDollhouse" class="button-dollhouse" @click="changeMode('dollhouse')">
-                    <ui-icon type="show_3d_normal"></ui-icon>
-                    <span> {{ $t('mode.dollhouseModel') }}</span>
-                </div>
-            </teleport>
-            <!-- <template v-if="refMiniMap && player.showWidgets"> -->
-            <template v-if="refMiniMap">
-                <div :class="{ disabled: flying }" v-show="mode != 'panorama'" v-if="controls.showFloorplan && controls.showDollhouse" class="tab-layer">
-                    <div class="tabs" v-if="controls.showMap">
-                        <span :class="{ active: mode === 'floorplan' }" ref="floorplan_ref" @click="changeMode('floorplan', $event)">
-                            <ui-icon :type="mode == 'floorplan' ? 'show_plane_selected' : 'show_plane_normal'"></ui-icon>
-                            {{ $t('mode.floorplan') }}
-                        </span>
-                        <span :class="{ active: mode === 'dollhouse' }" ref="dollhouse_ref" @click="changeMode('dollhouse', $event)">
-                            <ui-icon :type="mode == 'dollhouse' ? 'show_3d_selected' : 'show_3d_normal'"></ui-icon>
-
-                            {{ $t('mode.dollhouse') }}
-                        </span>
-                        <div class="background" ref="background"></div>
-                    </div>
-                </div>
-            </template>
+      <div class="scene" ref="scene$"></div>
+      <template v-if="dataLoaded">
+        <Information />
+        <Control />
+        <teleport v-if="refMiniMap && player.showWidgets" :to="refMiniMap">
+          <span class="button-switch" @click.stop="toggleMap">
+            <ui-icon type="show_map_collect"></ui-icon>
+          </span>
+  
+          <p class="change" v-if="controls.showDollhouse" @click="changeMode('dollhouse')">
+            <ui-icon type="show_3d_normal"></ui-icon>
+            3D模型
+          </p>
+        </teleport>
+        <template v-if="refMiniMap">
+          <div :class="{ disabled: flying }" v-show="mode != 'panorama'" v-if="controls.showFloorplan && controls.showDollhouse" class="tab-layer">
+            <div class="tabs" v-if="controls.showMap">
+              <span :class="{ active: mode === 'floorplan' }" ref="floorplan_ref" @click="changeMode('floorplan', $event)">
+                <ui-icon :type="mode == 'floorplan' ? 'show_plane_selected' : 'show_plane_normal'"></ui-icon>
+                二维
+              </span>
+              <span :class="{ active: mode === 'dollhouse' }" ref="dollhouse_ref" @click="changeMode('dollhouse', $event)">
+                <ui-icon :type="mode == 'dollhouse' ? 'show_3d_selected' : 'show_3d_normal'"></ui-icon>
+  
+                三维
+              </span>
+              <div class="background" ref="background"></div>
+            </div>
+          </div>
         </template>
-        <UiTags />
+      </template>
+      <UiTags />
     </div>
-</template>
-
-<script setup>
-import { useMusicPlayer } from '@/utils/sound'
-const musicPlayer = useMusicPlayer()
-import UiTags from '@/components/Tags'
-// import UiTags from '../../../kankan-editor/src/components/Tags'
-import Information from '@/components/Information'
-import Control from '@/components/Controls/Control.Mobile.vue'
-import Password from '@/components/shared/Password.vue'
-import Guide from '@/components/shared/Guide.vue'
-import LoadingLogo from '@/components/shared/Loading.vue'
-import { createApp } from '@/app'
-import { ref, onMounted, computed, watch, nextTick } from 'vue'
-import { useStore } from 'vuex'
-import browser from '@/utils/browser'
-import { useApp, getApp } from '@/app'
-import wxShare from '@/utils/wxshare'
-import common from '@/utils/common'
-import { useI18n, getLocale } from '@/i18n'
-const { t } = useI18n({ useScope: 'global' })
-const store = useStore()
-const player = computed(() => store.getters['player'])
-const flying = computed(() => store.getters['flying'])
-const metadata = computed(() => store.getters['scene/metadata'])
-const controls = computed(() => {
-    return metadata.value.controls
-})
-const getUrl = url => {
-    return common.changeUrl(url)
-}
-const getThumb = entry => {
-    let t = null
-    if (entry) {
-        t = getApp().resource.getUserResourceURL('thumb-1k.jpg', true)
-    }
-    return (t && getUrl(t)) || 'https://4dkk.4dage.com/v4/www/share-logo.jpg?t=' + new Date().getTime()
-}
-
-const mode = computed(() => store.getters['mode'])
-const showNavigations = computed(() => store.getters['showNavigations'])
-const scene$ = ref(null)
-const show = ref(false)
-const dataLoaded = ref(false)
-const refMiniMap = ref(null)
-const isCollapse = ref(false)
-const background = ref(null)
-const resize = () => {
-    if (this.$refs.background && (this.mode == 'floorplan' || this.mode == 'dollhouse')) {
-        this.$nextTick(() => {
-            let $active = $(this.$el).find('.tabs .active')
-            background.value.style.width = $active[0].getBoundingClientRect().width + 'px'
-            background.value.style.left = $active.position().left + 'px'
-        })
+  </template>
+  
+  <script setup>
+  import { useMusicPlayer } from "@/utils/sound";
+  import UiTags from "@/components/Tags";
+  
+  import Information from "@/components/Information";
+  import Control from "@/components/Controls/Control.Mobile.vue";
+  import LoadingLogo from "@/components/shared/Loading.vue";
+  import OpenVideo from "@/components/openVideo/";
+  import Guide from "@/components/shared/Guide.vue";
+  import Password from "@/components/shared/Password.vue";
+  
+  import { createApp } from "@/app";
+  import { ref, onMounted, computed, nextTick, watch } from "vue";
+  import { useStore } from "vuex";
+  import browser from "@/utils/browser";
+  import { useApp, getApp } from "@/app";
+  
+  const musicPlayer = useMusicPlayer();
+  
+  let app = null;
+  
+  const closetagtype = () => {
+    store.commit("tag/setTagClickType", {
+      type: "",
+      data: {},
+    });
+  };
+  
+  const store = useStore();
+  const tags = computed(() => {
+    return store.getters["tag/tags"] || [];
+  });
+  const player = computed(() => store.getters["player"]);
+  const flying = computed(() => store.getters["flying"]);
+  const metadata = computed(() => store.getters["scene/metadata"]);
+  const controls = computed(() => {
+    return metadata.value.controls;
+  });
+  const mode = computed(() => store.getters["mode"]);
+  const showNavigations = computed(() => store.getters["showNavigations"]);
+  const scene$ = ref(null);
+  const show = ref(false);
+  const dataLoaded = ref(false);
+  const refMiniMap = ref(null);
+  const isCollapse = ref(false);
+  const background = ref(null);
+  const resize = () => {
+    if (this.$refs.background && (this.mode == "floorplan" || this.mode == "dollhouse")) {
+      this.$nextTick(() => {
+        let $active = $(this.$el).find(".tabs .active");
+        background.value.style.width = $active[0].getBoundingClientRect().width + "px";
+        background.value.style.left = $active.position().left + "px";
+      });
     }
-}
-watch(
+  };
+  
+  watch(
     () => player.value.showMap,
     (val, old) => {
-        if (!isCollapse.value) {
-            let $minmap = document.querySelector('[xui_min_map]')
-            if ($minmap) {
-                if (val) {
-                    $minmap.classList.remove('collapse')
-                } else {
-                    $minmap.classList.add('collapse')
-                }
-            }
+      if (!isCollapse.value) {
+        let $minmap = document.querySelector("[xui_min_map]");
+        if ($minmap) {
+          if (val) {
+            $minmap.classList.remove("collapse");
+          } else {
+            $minmap.classList.add("collapse");
+          }
         }
+      }
     },
     {
-        deep: true
+      deep: true,
     }
-)
-watch(
-    () => mode.value,
+  );
+  watch(
+    () => player.value.showWidgets,
     (val, old) => {
-        console.log(val)
-        let timer = setTimeout(() => {
-            clearTimeout(timer)
-            if (val == 'floorplan') {
-                if (floorplan_ref.value && floorplan_ref.value) {
-                    background.value.style.width = floorplan_ref.value.getBoundingClientRect().width + 'px'
-                    background.value.style.left = floorplan_ref.value.offsetLeft + 'px'
-                }
-            } else if (val == 'dollhouse') {
-                if (dollhouse_ref.value && dollhouse_ref.value) {
-                    background.value.style.width = dollhouse_ref.value.getBoundingClientRect().width + 'px'
-                    background.value.style.left = dollhouse_ref.value.offsetLeft + 'px'
-                }
-            }
-        }, 0)
+      let $minmap = document.querySelector("[xui_min_map]");
+      if ($minmap) {
+        if (val) {
+          $minmap.classList.remove("collapse");
+        } else {
+          $minmap.classList.add("collapse");
+        }
+      }
     },
     {
-        deep: true
+      deep: true,
     }
-)
-watch(
-    () => player.value.showWidgets,
+  );
+  
+  watch(
+    () => mode.value,
     (val, old) => {
-        let $minmap = document.querySelector('[xui_min_map]')
-        if ($minmap) {
-            if (val) {
-                $minmap.classList.remove('collapse')
-            } else {
-                $minmap.classList.add('collapse')
-            }
+      console.log(val);
+      let timer = setTimeout(() => {
+        clearTimeout(timer);
+        if (val == "floorplan") {
+          if (floorplan_ref.value && floorplan_ref.value) {
+            background.value.style.width = floorplan_ref.value.getBoundingClientRect().width + "px";
+            background.value.style.left = floorplan_ref.value.offsetLeft + "px";
+          }
+        } else if (val == "dollhouse") {
+          if (dollhouse_ref.value && dollhouse_ref.value) {
+            background.value.style.width = dollhouse_ref.value.getBoundingClientRect().width + "px";
+            background.value.style.left = dollhouse_ref.value.offsetLeft + "px";
+          }
         }
+      }, 0);
     },
     {
-        deep: true
+      deep: true,
     }
-)
-const floorplan_ref = ref(null)
-const dollhouse_ref = ref(null)
-const changeMode = (name, e) => {
+  );
+  
+  const floorplan_ref = ref(null);
+  const dollhouse_ref = ref(null);
+  const changeMode = (name, e) => {
     if (e) {
-        if (!flying.value) {
-            // background.value.style.width = e.srcElement.getBoundingClientRect().width + 'px'
-            // background.value.style.left = e.srcElement.offsetLeft + 'px'
-            store.commit('setMode', name)
-        }
+      if (!flying.value) {
+        // background.value.style.width = e.srcElement.getBoundingClientRect().width + 'px'
+        // background.value.style.left = e.srcElement.offsetLeft + 'px'
+        store.commit("setMode", name);
+      }
     } else {
-        // let t = setTimeout(() => {
-        // background.value.style.width = dollhouse_ref.value.getBoundingClientRect().width + 'px'
-        // background.value.style.left = dollhouse_ref.value.offsetLeft + 'px'
-        store.commit('setMode', name)
-        // }, 0)
+      // let t = setTimeout(() => {
+      // background.value.style.width = dollhouse_ref.value.getBoundingClientRect().width + 'px'
+      // background.value.style.left = dollhouse_ref.value.offsetLeft + 'px'
+      store.commit("setMode", name);
+      // }, 0)
     }
-}
-const toggleMap = () => {
-    isCollapse.value = !isCollapse.value
-    let $minmap = document.querySelector('[xui_min_map]')
+  };
+  // console.dir(document.querySelector(".tabs>span:last-of-type"));
+  const toggleMap = () => {
+    isCollapse.value = !isCollapse.value;
+    let $minmap = document.querySelector("[xui_min_map]");
     if ($minmap) {
-        if (!isCollapse.value) {
-            $minmap.classList.remove('collapse')
-        } else {
-            $minmap.classList.add('collapse')
-        }
+      if (!isCollapse.value) {
+        $minmap.classList.remove("collapse");
+      } else {
+        $minmap.classList.add("collapse");
+      }
+    }
+  };
+  
+  const onClickTagInfo = (el) => {
+    el.stopPropagation();
+    let item = tags.value.find((item) => item.sid == el.target.dataset.id);
+    if (item.type == "commodity") {
+      store.commit("tag/setTagClickType", {
+        type: "goodlist",
+        data: item,
+      });
     }
-}
-onMounted(() => {
+  };
+  
+  onMounted(() => {
     const app = createApp({
-        num: browser.getURLParam('m'),
-        dom: scene$.value,
-        mobile: true,
-        lang: getLocale(),
-        langs: {
-            en: {
-                'model.enter': t('model.enter')
+      num: browser.getURLParam("m"),
+      dom: scene$.value,
+      mobile: true,
+    });
+    app.Scene.lock();
+    app.use("MinMap", { theme: { camera_fillStyle: "#0076f6" } });
+    app.use("Tag");
+    app.use("TourPlayer");
+    app.Scene.on("ready", () => {
+      show.value = true;
+    });
+    app.Scene.on("error", (data) => {
+      console.error(data);
+      switch (data.code) {
+        case 5033:
+          window.location.replace(`/5033.html?m=` + browser.getURLParam("m"));
+          break;
+        case 5034:
+          window.location.replace(`/5034.html?m=` + browser.getURLParam("m"));
+          break;
+        case 5009:
+          window.location.replace(`/5034.html?m=` + browser.getURLParam("m"));
+          break;
+        case 5005:
+          window.location.replace(`/#/404.html?m=` + browser.getURLParam("m"));
+          break;
+      }
+    });
+    app.Scene.on("loaded", (pano) => {
+      refMiniMap.value = "[xui_min_map]";
+      store.commit("setFloorId", pano.floorIndex);
+      useMusicPlayer();
+    });
+    app.Scene.on("panorama.videorenderer.resumerender", () => {
+      musicPlayer.pause(true);
+    });
+  
+    app.Scene.on("panorama.videorenderer.suspendrender", async () => {
+      let player = await getApp().TourManager.player;
+      if (!player.isPlaying) {
+        musicPlayer.resume();
+      }
+    });
+    app.store.on("metadata", (metadata) => {
+      let div = document.createElement("div");
+      div.innerHTML = metadata.description;
+      store.commit("scene/load", metadata);
+      if (!metadata.controls.showMap) {
+        app.MinMap.hide(true);
+      }
+      dataLoaded.value = true;
+    });
+    app.store.on("tags", (tags) => {
+      store.commit("tag/load", tags);
+    });
+    app.Camera.on("mode.beforeChange", ({ fromMode, toMode, floorIndex }) => {
+      if (fromMode) {
+        store.commit("setFlying", true);
+      }
+    });
+    app.Camera.on("mode.afterChange", ({ toMode, floorIndex }) => {
+      store.commit("setFlying", false);
+    });
+    app.Camera.on("flying.started", (pano) => {
+      store.commit("setFlying", true);
+    });
+    app.Camera.on("flying.ended", ({ targetPano }) => {
+      store.commit("setFlying", false);
+      store.commit("setPanoId", targetPano.id);
+    });
+    app.store.on("tour", async (tour) => {
+      app.TourManager.load(tour);
+      store.commit("tour/setData", {
+        tours: JSON.parse(
+          JSON.stringify(app.TourManager.tours, (key, val) => {
+            if (key === "audio") {
+              return null;
+            } else {
+              return val;
             }
-        }
-    })
-    app.Scene.lock()
-    app.use('MinMap')
-    app.use('Tag')
-    app.use('TourPlayer')
-    app.Scene.on('ready', () => {
-        show.value = true
-    })
-    app.Scene.on('error', data => {
-        console.error(data)
-        switch (data.code) {
-            case 5033:
-                window.location.replace(`/5033.html?m=` + browser.getURLParam('m'))
-                break
-            case 5034:
-                window.location.replace(`/5034.html?m=` + browser.getURLParam('m'))
-                break
-            case 5009:
-                window.location.replace(`/5034.html?m=` + browser.getURLParam('m'))
-                break
-            case 5005:
-                window.location.replace(`/#/404.html?m=` + browser.getURLParam('m'))
-                break
-        }
-    })
-    app.Scene.on('loaded', pano => {
-        refMiniMap.value = '[xui_min_map]'
-        store.commit('setFloorId', pano.floorIndex)
-        useMusicPlayer()
-    })
-    app.Scene.on('panorama.videorenderer.resumerender', () => {
-        musicPlayer.pause(true)
-    })
-
-    app.Scene.on('panorama.videorenderer.suspendrender', async () => {
-        let player = await getApp().TourManager.player
-        if (!player.isPlaying) {
-            musicPlayer.resume()
-        }
-    })
-    app.store.on('metadata', metadata => {
-        let div = document.createElement('div')
-        div.innerHTML = metadata.description
-        wxShare({
-            // title: `VR空间 [${metadata.title}]`,
-            // desc: '实景三维相机结合 AI 算法为您还原真实世界',
-            title: `${metadata.title}`,
-            desc: div.innerText,
-            link: window.location.href.split('#')[0],
-            imgUrl: getThumb(metadata.entry)
-        })
-        store.commit('scene/load', metadata)
-        if (!metadata.controls.showMap) {
-            app.MinMap.hide(true)
-        }
-        dataLoaded.value = true
-    })
-    app.store.on('tags', tags => {
-        store.commit('tag/load', tags)
-    })
-    app.Camera.on('mode.beforeChange', ({ fromMode, toMode, floorIndex }) => {
-        if (fromMode) {
-            store.commit('setFlying', true)
-        }
-    })
-    app.Camera.on('mode.afterChange', ({ toMode, floorIndex }) => {
-        store.commit('setFlying', false)
-    })
-    app.Camera.on('flying.started', pano => {
-        store.commit('setFlying', true)
-    })
-    app.Camera.on('flying.ended', ({ targetPano }) => {
-        store.commit('setFlying', false)
-        store.commit('setPanoId', targetPano.id)
-    })
-    app.store.on('tour', async tour => {
-        app.TourManager.load(tour)
-        store.commit('tour/setData', {
-            tours: JSON.parse(
-                JSON.stringify(app.TourManager.tours, (key, val) => {
-                    if (key === 'audio') {
-                        return null
-                    } else {
-                        return val
-                    }
-                })
-            )
-        })
-        store.commit('tour/setBackUp', {
-            tours: JSON.parse(
-                JSON.stringify(app.TourManager.tours, (key, val) => {
-                    if (key === 'audio') {
-                        return null
-                    } else {
-                        return val
-                    }
-                })
-            )
-        })
-    })
-    app.store.on('floorcad', floor => store.commit('scene/loadFloorData', floor))
-
-    app.render()
-})
-</script>
-<style lang="scss">
-.tab-layer {
+          })
+        ),
+      });
+      store.commit("tour/setBackUp", {
+        tours: JSON.parse(
+          JSON.stringify(app.TourManager.tours, (key, val) => {
+            if (key === "audio") {
+              return null;
+            } else {
+              return val;
+            }
+          })
+        ),
+      });
+    });
+    app.store.on("floorcad", (floor) => store.commit("scene/loadFloorData", floor));
+  
+    app.render();
+  });
+  </script>
+  
+  <style lang="scss">
+  .tab-layer {
     width: 100%;
     text-align: center;
     display: flex;
@@ -307,8 +310,8 @@ onMounted(() => {
     transform: translateX(-50%);
     top: 2.3rem;
     pointer-events: none;
-}
-.tabs {
+  }
+  .tabs {
     pointer-events: auto;
     position: relative;
     display: flex;
@@ -320,53 +323,164 @@ onMounted(() => {
     border: 1px solid rgba(255, 255, 255, 0.1);
     box-shadow: inset 0px 0px 6px 0px rgba(0, 0, 0, 0.5);
     .background {
-        position: absolute;
-        left: 2px;
-        top: 2px;
-        bottom: 2px;
-        width: 50%;
-        border-radius: 4px;
-        background: #444444;
-        box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.3);
-        z-index: 0;
-        transition: left 0.3s;
+      position: absolute;
+      left: 2px;
+      top: 2px;
+      bottom: 2px;
+      width: 50%;
+      border-radius: 4px;
+      background: #444444;
+      box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.3);
+      z-index: 0;
+      transition: left 0.3s;
     }
     span {
-        flex: 1;
-        color: #fff;
-        opacity: 0.5;
-        border-radius: 6px;
-        height: 0.94737rem;
-        font-size: 0.36842rem;
-        transition: all 0.3s ease;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        padding-left: 10px;
-        padding-right: 10px;
-        white-space: nowrap;
-        z-index: 1;
-        i {
-            font-size: 0.47368rem;
-            margin-right: 4px;
-            pointer-events: none;
-        }
+      flex: 1;
+      color: #fff;
+      opacity: 0.5;
+      border-radius: 6px;
+      height: 0.94737rem;
+      font-size: 0.36842rem;
+      transition: all 0.3s ease;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      padding-left: 10px;
+      padding-right: 10px;
+      white-space: nowrap;
+      z-index: 1;
+      i {
+        font-size: 0.47368rem;
+        margin-right: 4px;
+        pointer-events: none;
+      }
     }
-
+  
     span.active {
-        opacity: 1;
+      opacity: 1;
+    }
+  }
+  
+  [xui_tags_view] {
+    .tag-body {
+      /* display: none; */
+      position: absolute;
+      left: 50%;
+      bottom: 50px;
+      transform: translateX(-50%) scale(0);
+      transform-origin: bottom;
+      transition: all 0.3s cubic-bezier(0.35, 0.32, 0.65, 0.63);
+      // pointer-events: none;
+      .tag-commodity {
+        min-width: 230px;
+        height: 76px;
+        background: rgba(255, 255, 255, 0.8);
+        box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.16);
+        border-radius: 2px;
+        position: relative;
+        margin-bottom: 30px;
+        &::before {
+          content: "";
+          display: inline-block;
+          left: 50%;
+          transform: translateX(-50%);
+          width: 2px;
+          height: 28px;
+          bottom: -30px;
+          background: linear-gradient(145deg, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0));
+          position: absolute;
+        }
+        .tag-avatar {
+          position: absolute;
+          z-index: 99;
+          width: 80px;
+          height: 80px;
+          background: #ffffff;
+          box-shadow: 0px 3px 6px 0px rgb(0 0 0 / 16%);
+          border-radius: 2px;
+          top: -14px;
+          left: -12px;
+          background-size: cover;
+          pointer-events: none;
+        }
+        > p {
+          color: #131d34;
+          font-size: 16px;
+          pointer-events: none;
+        }
+        .tag-title {
+          padding: 10px 10px 10px 76px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          width: 240px;
+        }
+        .tag-info {
+          padding: 0 20px 0 76px;
+          font-size: 12px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+      }
+      &.show {
+        transform: translateX(-50%) scale(1);
+      }
+    }
+  
+    .coupon {
+      width: 64px !important;
+      height: 64px !important;
+      &::after {
+        content: "發現好禮";
+        width: 100%;
+        color: #ed5d18;
+        position: absolute;
+        bottom: -24px;
+        text-align: center;
+        font-size: 14px;
+      }
+    }
+  
+    .waterfall {
+      width: 70px !important;
+      height: 70px !important;
     }
-}
-@media (orientation: landscape) {
+  
+    .applet_link {
+      width: 64px !important;
+      height: 64px !important;
+      border-radius: 50%;
+      background-color: #fff;
+      border: 1px solid #ed5d18;
+      position: relative;
+      overflow: hidden;
+      &::after {
+        content: "直播中";
+        width: 100%;
+        height: 20px;
+        background: #ed5d18;
+        position: absolute;
+        bottom: 0;
+        text-align: center;
+        line-height: 1.2;
+        font-size: 12px;
+        border-radius: 26%;
+      }
+    }
+  }
+  
+  @media (orientation: landscape) {
     .tab-layer {
-        top: 1.2rem;
-        .tabs {
-            height: 0.7rem;
-            > span {
-                height: 0.7rem;
-                font-size: 0.25rem;
-            }
+      top: 1.2rem;
+      .tabs {
+        height: 0.7rem;
+        > span {
+          height: 0.7rem;
+          font-size: 0.25rem;
         }
+      }
     }
-}
-</style>
+  }
+  </style>
+  

+ 0 - 8
packages/qjkankan-kankan-view/src/pages/SPG.vue

@@ -23,8 +23,6 @@ import { ref, onMounted } from 'vue'
 import { useStore } from 'vuex'
 import { useApp, getApp } from '@/app'
 import browser from '@/utils/browser'
-import { useI18n, getLocale } from '@/i18n'
-const { t } = useI18n({ useScope: 'global' })
 
 const store = useStore()
 const show = ref(false)
@@ -34,12 +32,6 @@ onMounted(() => {
     const app = createApp({
         num: browser.getURLParam('m'),
         dom: scene$.value,
-        lang: getLocale(),
-        langs: {
-            en: {
-                'model.enter': t('model.enter'),
-            },
-        },
     })
     app.use('MinMap')
     app.use('Tag')

+ 12 - 32
packages/qjkankan-kankan-view/src/pages/smg.js

@@ -1,33 +1,13 @@
-import '@/assets/theme.editor.scss'
-import ClickOutSide from '../utils/fns/ClickOutSide'
-import Components from '@qjkankan/components'
-import { createApp } from 'vue'
-import browser from '../utils/browser'
-import store from '../store'
-import SMG from './SMG.vue'
-import Checkbrowser from '../components/shared/Checkbrowser.vue'
-import { IsApp } from '@/utils/platform'
-import i18n, { getLocale, setI18nLanguage, loadLocaleMessages } from '../i18n'
+import "@/assets/theme.editor.scss";
+import ClickOutSide from "@/utils/fns/ClickOutSide";
+import Components from "@/global_components";
+import { createApp } from "vue";
+import store from "@/store";
+import App from "./SMG.vue";
 
-let App
-if (browser.detectChrome() || browser.detectSafari() || browser.detectFirefox() || browser.detectEdge() || browser.detectWeixin() || browser.detectWeixinMiniProgram() || browser.detectAlipay()) {
-    App = SMG
-} else {
-    if (IsApp) {
-        App = SMG
-    } else {
-        App = Checkbrowser
-    }
-}
-
-const local = getLocale()
-loadLocaleMessages(i18n, local).then(() => {
-    setI18nLanguage(i18n, local)
-
-    const app = (window.__app = createApp(App))
-    app.use(i18n)
-    app.use(store)
-    app.use(Components)
-    app.directive('click-outside', ClickOutSide)
-    app.mount('#app')
-})
+const app = createApp(App);
+// set i18n language
+app.use(store);
+app.use(Components);
+app.directive("click-outside", ClickOutSide);
+app.mount("#app");

+ 12 - 31
packages/qjkankan-kankan-view/src/pages/spg.js

@@ -1,32 +1,13 @@
-import '@/assets/theme.editor.scss'
-import ClickOutSide from '../utils/fns/ClickOutSide'
-import browser from '../utils/browser'
-import Components from '@qjkankan/components'
-import { createApp } from 'vue'
-import store from '../store'
-import Spg from './SPG.vue'
-import Checkbrowser from '../components/shared/Checkbrowser.vue'
-import i18n, { getLocale, setI18nLanguage, loadLocaleMessages } from '../i18n'
-import { IsApp } from '@/utils/platform'
-let App
-if (browser.detectChrome() || browser.detectSafari() || browser.detectFirefox() || browser.detectEdge() || browser.detectWeixin() || browser.detectWeixinMiniProgram() || browser.detectAlipay()) {
-    App = Spg
-} else {
-    if (IsApp) {
-        App = SMG
-    } else {
-        App = Checkbrowser
-    }
-}
+import "@/assets/theme.editor.scss";
+import ClickOutSide from "@/utils/fns/ClickOutSide";
+import Components from "@/global_components";
+import { createApp } from "vue";
+import store from "@/store";
+import App from "./SPG.vue";;
 
-const local = getLocale()
-loadLocaleMessages(i18n, local).then(() => {
-    setI18nLanguage(i18n, local)
-
-    const app = (window.__app = createApp(App))
-    app.use(i18n)
-    app.use(store)
-    app.use(Components)
-    app.directive('click-outside', ClickOutSide)
-    app.mount('#app')
-})
+const app = createApp(App);
+// set i18n language
+app.use(store);
+app.use(Components);
+app.directive("click-outside", ClickOutSide);
+app.mount("#app");

+ 2 - 1
packages/qjkankan-kankan-view/vue.config.js

@@ -9,7 +9,8 @@ module.exports = defineConfig({
   publicPath: "./",
   outputDir: isDev ? 'dist' : path.resolve('../../dist'),
   pages: {
-    smg: 'src/main.js',
+    spg: 'src/pages/spg.js',
+    smg: 'src/pages/smg.js',
   },
   css: {
     extract: false,

+ 0 - 18
packages/qjkankan-view/public/index.html

@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html lang="">
-  <head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width,initial-scale=1.0">
-    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-    <title><%= htmlWebpackPlugin.options.title %></title>
-  </head>
-  <body>
-    <noscript>
-      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
-    </noscript>
-    <div id="app"></div>
-    <!-- built files will be auto injected -->
-  </body>
-</html>
-

+ 4 - 4
packages/qjkankan-view/public/static/lib/krpano/plugins/webvr.xml

@@ -180,7 +180,7 @@
 	</action>
 	
 	<action name="webvr_show_fakemode_info">
-		if('%1' == 'true',
+		<!-- if('%1' == 'true',
 			addlayer(webvr_fakemode_info);
 			set(layer[webvr_fakemode_info].url, '%SWFPATH%/plugins/textfield.swf');
 			set(layer[webvr_fakemode_info].keep, true);
@@ -191,7 +191,7 @@
 			set(layer[webvr_fakemode_info].html, '[i][u]Simulated WebVR Mode![/u][/i][br]For real WebVR with headset tracking, either use a [a href="http://webvr.info" target="_blank" style="color:#FFFFFF;"]WebVR-API-capable[/a] desktop browser or a mobile device and a VR headset.');
 		  ,
 			removelayer(webvr_fakemode_info);
-		  );
+		  ); -->
 	</action>
 	
 	
@@ -222,7 +222,7 @@
 
 	<layer name="webvr_exitbutton" keep="true" vr="true"
 	       style="webvr_button_style"
-	       html="Exit VR"
+	       html="退出VR"
 	       align="top" y="24"
 	       autoalpha="true" alpha="0.0"
 	       onclick="webvr.exitVR();"
@@ -230,7 +230,7 @@
 
 	<layer name="webvr_setupbutton" keep="true" vr="true"
 	       style="webvr_button_style"
-	       html="VR Setup"
+	       html="VR设置"
 	       align="bottom" y="24"
 	       autoalpha="true" alpha="0.0"
 	       onclick="vr_setup()"

+ 19 - 0
packages/qjkankan-view/public/static/lib/krpano/tour.xml

@@ -123,5 +123,24 @@
 	</scene>
 
 
+<scene name="scene_fd720_HLWHObl0I" title="fd720_HLWHObl0I" onstart="" thumburl="https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/720yun_fd_manage/fd720_HLWHObl0I/vtour/panos/fd720_HLWHObl0I.tiles/thumb.jpg" lat="" lng="" heading="">
+<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto"/>
+<preview url="https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/720yun_fd_manage/fd720_HLWHObl0I/vtour/panos/fd720_HLWHObl0I.tiles/preview.jpg"/>
+		<image type="CUBE" multires="true" tilesize="512">
+		<level tiledimagewidth="5184" tiledimageheight="5184">
+		<cube url="https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/720yun_fd_manage/fd720_HLWHObl0I/vtour/panos/fd720_HLWHObl0I.tiles/%s/l4/%v/l4_%s_%v_%h.jpg"/>
+		</level>
+		<level tiledimagewidth="2624" tiledimageheight="2624">
+		<cube url="https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/720yun_fd_manage/fd720_HLWHObl0I/vtour/panos/fd720_HLWHObl0I.tiles/%s/l3/%v/l3_%s_%v_%h.jpg"/>
+		</level>
+		<level tiledimagewidth="1280" tiledimageheight="1280">
+		<cube url="https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/720yun_fd_manage/fd720_HLWHObl0I/vtour/panos/fd720_HLWHObl0I.tiles/%s/l2/%v/l2_%s_%v_%h.jpg"/>
+		</level>
+		<level tiledimagewidth="640" tiledimageheight="640">
+		<cube url="https://oss-xiaoan.oss-cn-shenzhen.aliyuncs.com/720yun_fd_manage/fd720_HLWHObl0I/vtour/panos/fd720_HLWHObl0I.tiles/%s/l1/%v/l1_%s_%v_%h.jpg"/>
+		</level>
+		</image>
+</scene>
+
 
  </krpano>

+ 25 - 0
packages/qjkankan-view/src/components/Fdkk/index.vue

@@ -0,0 +1,25 @@
+<template>
+  <div class="fdkkcon">
+    <iframe src="https://www.4dkankan.com/spc.html?m=SS-0UKHRqfv0r" frameborder="0"></iframe>
+  </div>
+</template>
+
+<script setup>
+  
+</script>
+
+<style lang="scss" scoped>
+.fdkkcon{
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  >iframe{
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 37 - 21
packages/qjkankan-view/src/components/Pano/index.vue


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

@@ -141,6 +141,7 @@ $width: 1150px;
   overflow: hidden;
   max-height: 0;
   transition: .3s all ease;
+  z-index: 9;
   .swiper-container {
     width: 100%;
     position: relative;
@@ -171,6 +172,7 @@ $width: 1150px;
   .top-con {
     margin-bottom: 10px;
     padding: 10px 30px;
+    min-width: 400px;
     background: linear-gradient(268deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.5) 8%, rgba(0, 0, 0, 0.5) 92%, rgba(0, 0, 0, 0) 100%);
   }
 

+ 1 - 0
packages/qjkankan-view/src/components/UIGather/menu.vue

@@ -29,6 +29,7 @@ onMounted(() => {
   left: 20px;
   bottom: 8px;
   display: flex;
+  z-index: 9;
   > li {
     width: 36px;
     height: 36px;

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

@@ -3,7 +3,7 @@
     <div
       v-if="show"
       class="scene-loading"
-      :class="{ small: small, thumb: props.thumb, default: thumbStyle }"
+      :class="{ small: small, thumb: props.thumb }"
       @touchmove.prevent
       :style="metadata.icon && { backgroundImage: `url(${metadata.icon})` }"
     >

+ 2 - 1
packages/qjkankan-view/src/pages/show.vue

@@ -27,6 +27,7 @@ import { createApp } from "@/app";
 import { ref, onMounted, computed, watch, nextTick } from "vue";
 import { getPanoInfo, checkWork } from "@/apis";
 import { useStore } from "vuex";
+import config from "@/utils/config";
 
 const store = useStore();
 const show = ref(false);
@@ -68,7 +69,7 @@ onMounted(async () => {
 
     const app = createApp({
       // xml: "%HTMLPATH%/static/template/tour.xml",
-      xml: `${process.env.VUE_APP_CDN}/720yun_fd_manage/${currentScene.value.sceneCode}/vtour/tour.xml`,
+      xml: `${process.env.VUE_APP_CDN}/720yun_fd_manage/${config.projectNum}/tour.xml`,
       swf: "%HTMLPATH%/static/lib/krpano/tour.swf",
       target: "pano",
       html5: "auto",

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 381 - 244
yarn.lock