gemercheung 2 سال پیش
والد
کامیت
400bdff073

+ 2 - 1
.env.development

@@ -3,7 +3,8 @@ VITE_APP_RESOURCE_URL=https://4dkk.4dage.com/
 # 静态资源地址
 VITE_APP_CDN_URL=https://4dkk.4dage.com/v4/www/
 # sdk文件地址
-VITE_APP_SDK_DIR=https://4dkk.4dage.com/v4/sdk/4.9.0
+# VITE_APP_SDK_DIR=https://4dkk.4dage.com/v4/sdk/4.9.0
+VITE_APP_SDK_DIR=https://4dkk.4dage.com/v4-test/www/sdk
 # VITE_APP_SOCKET_URL=ws://127.0.0.1:8889
 VITE_APP_SOCKET_URL=wss://testws.4dkankan.com
 # VITE_APP_SOCKET_URL=wss://221.4.210.172:16666

+ 55 - 55
src/assets/theme.editor.scss

@@ -203,10 +203,63 @@ input[type='password']::-ms-reveal {
 a {
   color: #ed5d18;
 }
-
 [xui_min_map] {
-  top: 20px !important;
+  width: 150px !important;
+  height: 150px !important;
+  top: 80px !important;
   right: 20px !important;
+  background-color: rgba(0, 0, 0, 0.2) !important;
+  border-radius: 4px 4px 0 0 !important;
+  border-top-left-radius: 0 !important;
+  transition: all 0.3s;
+  &.collapse {
+    transform: translateX(calc(100% + 15px));
+    .button-switch {
+      > .iconfont {
+        font-size: 12px;
+        transform: rotate(180deg) scale(0.7);
+      }
+    }
+  }
+  .button-switch {
+    position: absolute;
+    top: 0;
+    left: -16px;
+    background-color: rgba(0, 0, 0, 0.2);
+    height: 32px;
+    width: 16px;
+    border-radius: 32px 0 0 32px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    transition: rotate 0.3s;
+    > .iconfont {
+      font-size: 12px;
+      transform: scale(0.7);
+    }
+  }
+  .change {
+    position: absolute;
+    bottom: -29px;
+    left: 0;
+    height: 28px;
+    background-color: rgba(0, 0, 0, 0.2);
+    width: 100%;
+    text-align: center;
+    margin: 0;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 0 0 4px 4px !important;
+    > i {
+      margin-right: 4px;
+    }
+  }
+}
+
+[is-mobile] [xui_min_map] {
+  width: 100px !important;
+  height: 100px !important;
 }
 .slider-box {
   position: fixed;
@@ -259,59 +312,6 @@ a {
 }
 
 [is-mobile] {
-  [xui_min_map] {
-    width: 100px;
-    height: 100px;
-    top: 2.3rem !important;
-    right: 15px !important;
-    background-color: rgba(0, 0, 0, 0.2) !important;
-    border-radius: 4px 4px 0 0 !important;
-    border-top-left-radius: 0 !important;
-    transition: all 0.3s;
-    &.collapse {
-      transform: translateX(calc(100% + 15px));
-      .button-switch {
-        > .iconfont {
-          font-size: 12px;
-          transform: rotate(180deg) scale(0.7);
-        }
-      }
-    }
-    .button-switch {
-      position: absolute;
-      top: 0;
-      left: -16px;
-      background-color: rgba(0, 0, 0, 0.2);
-      height: 32px;
-      width: 16px;
-      border-radius: 32px 0 0 32px;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      transition: rotate 0.3s;
-      > .iconfont {
-        font-size: 12px;
-        transform: scale(0.7);
-      }
-    }
-    .change {
-      position: absolute;
-      bottom: -29px;
-      left: 0;
-      height: 28px;
-      background-color: rgba(0, 0, 0, 0.2);
-      width: 100%;
-      text-align: center;
-      margin: 0;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      border-radius: 0 0 4px 4px !important;
-      > i {
-        margin-right: 4px;
-      }
-    }
-  }
   .ui-dialog {
     .ui-dialog__box {
       min-width: 100px;

+ 93 - 83
src/components/hotspot/index.vue

@@ -6,20 +6,25 @@
         @mouseleave.prevent="onMouseLeave($event, tag)"
         :style="{
           transform: `translate3d(${tag.x}px,${tag.y}px,0)`,
-          'z-index': 1,
+          'z-index': isShowTag(tag) ? 1 : 0,
         }"
         :class="{
-          visible: true,
+          visible: tag.visible,
         }"
       >
         <span
           class="point zoom"
-          @mouseenter.prevent="onMouseEnter($event, tag, index)"
+          @mouseenter.prevent="onMouseEnter($event, tag)"
           @click.stop="goTag($event, tag, index)"
           :style="{ 'background-image': 'url(' + getUrl(tag.icon) + ')' }"
         ></span>
         <div class="content">
-          <div class="trans">
+          <div
+            class="trans"
+            :class="{
+              active: isShowTag(tag),
+            }"
+          >
             <!-- :class="{
               fixed: isPlay,
               active:
@@ -28,9 +33,12 @@
             }" -->
             <template v-if="tag && !showMsg">
               <div class="arrow" :id="`arrow_${tag.sid}`">
-                <!-- <ui-icon @click.stop="closeTag" type="close" /> -->
+                <i
+                  @click.stop="closeTag"
+                  class="iconfont ui-kankan-icon icon tip-h-center tip-v-bottom icon-close"
+                ></i>
               </div>
-              <!-- <ShowTag @click.stop="" v-if="tag" @open="openInfo" /> -->
+              <ShowTag @click.stop="" :tag="tag" v-if="tag" @open="openInfo" />
             </template>
           </div>
         </div>
@@ -41,8 +49,8 @@
   </teleport>
 </template>
 <script setup lang="ts">
-  import { ref, onMounted, nextTick } from 'vue';
-  import { useSceneStore } from '/@/store/modules/scene';
+  import { ref, onMounted, nextTick, unref } from 'vue';
+  import { useSceneStore, tagType } from '/@/store/modules/scene';
   import { computed } from 'vue';
   import { getApp, useApp } from '/@/hooks/userApp';
   import browser from '/@/utils/browser';
@@ -51,70 +59,49 @@
   import { changeUrl } from './common';
   import { watchEffect } from 'vue';
   // import TagView from './tag-view.vue';
-  // import ShowTag from './show-tag.vue';
-  // import { useRoute } from 'vue-router';
-  // import { useMusicPlayer } from '@/utils/sound';
-  // import browser from '@/utils/browser';
-  // import { Track, startTrack, endTrack } from "@/utils/track.js";
-  // const musicPlayer = useMusicPlayer();
+  import ShowTag from './show-tag.vue';
   const sceneStore = useSceneStore();
   const tags$ = ref('');
   const tags = computed(() => sceneStore.tags);
 
-  const showInfo = ref(false);
+  const showInfo = ref<tagType | null>(null);
+  const isClick = ref(false);
   const showMsg = ref(false);
+  const isShowTag = computed(() => {
+    return (tag: tagType) => {
+      return showInfo.value && showInfo.value.sid === tag.sid;
+    };
+  });
   // const toggleIndex = ref(null)
   const openInfo = () => {
     showMsg.value = true;
-    store.commit('tag/setData', { isFixed: false, isClick: true });
-    showInfo.value = false;
-  };
-  const closeInfo = () => {
-    showMsg.value = false;
-    if (isClick.value) {
-      //只有点击定位的才恢复显示
-      store.commit('tag/show', toggleIndex.value);
-      store.commit('tag/setFixed', true);
-      // showInfo.value = true
-      showInfo.value = false;
-    }
-    // store.commit('tag/setClick', false)
+    // store.commit('tag/setData', { isFixed: false, isClick: true });
+    showInfo.value = null;
   };
+  const closeInfo = () => {};
+
   const closeTag = async () => {
-    const app = getApp();
-    const player = await app.TourManager.player;
+    showInfo.value = null;
+    isClick.value = false;
+  };
 
-    //关闭热点面板时候,继续播放之前暂停的音频
-    if (!app.Scene.isCurrentPanoHasVideo && !player.isPlaying) {
-      if (hotData.value.type == 'audio' || hotData.value.type == 'video') {
-        // console.log('resume')
-        window.parent.postMessage(
-          {
-            source: 'qjkankan',
-            event: 'toggleBgmStatus',
-            params: {
-              status: true,
-            },
-          },
-          '*',
-        );
-      }
+  const goTag = async (_, item: tagType) => {
+    // const app = await useApp();
+    if (unref(isClick)) {
+      showInfo.value = null;
+      isClick.value = false;
+    } else {
+      isClick.value = true;
+      focusTag(item);
     }
-    // store.commit('tag/setData', { isFixed: false, isClick: false, flyClose: false })
-    store.commit('tag/setData', { isFixed: false, isClick: false });
-    store.commit('tag/closeTag');
-
-    // store.commit('tag/setFixed', false)
-    // store.commit('tag/closeTag')
-    // store.commit('tag/setClick', false)
-    showInfo.value = false;
   };
-  const goTag = async (event, item, index) => {};
-  const onMouseLeave = (...arg) => {
-    console.log(arg);
+  const onMouseLeave = (_, tag: tagType) => {
+    if (!unref(isClick) && showInfo.value?.sid === tag.sid) {
+      showInfo.value = null;
+    }
   };
-  const onMouseEnter = (...arg) => {
-    console.log(arg);
+  const onMouseEnter = (_, tag: tagType) => {
+    showInfo.value = tag;
   };
 
   onMounted(async () => {
@@ -126,34 +113,26 @@
     watchEffect(() => {
       if (tags.value?.length) {
         app.TagManager.load(tags.value);
+        app.TagManager.updatePosition(tags.value);
       }
     });
-    app.Camera.on('flying.started', (pano) => {
-      // if (!pano.isTagFlying && hotData.value && !isEdit.value) {
-      //   closeTag();
-      // }
-      // if (flyClose.value && hotData.value && !isEdit.value) {
-      //     getApp().TagManager.close(hotData.value.sid)
-      //     closeTag()
-      // }
-    });
-    app.Scene.on('loadeddata', () => {
-      if (browser.hasURLParam('t_id')) {
-        let t_id = browser.getURLParam('t_id');
-        for (let i = 0; i < tags.value.length; i++) {
-          if (tags.value[i].sid == t_id) {
-            goTag({}, tags.value[i], i);
-          }
-        }
-      }
-    });
+    app.Camera.on('flying.started', (pano) => {});
+    // app.Scene.on('loadeddata', () => {
+    //   if (browser.hasURLParam('t_id')) {
+    //     let t_id = browser.getURLParam('t_id');
+    //     for (let i = 0; i < tags.value.length; i++) {
+    //       if (tags.value[i].sid == t_id) {
+    //         goTag({}, tags.value[i], i);
+    //       }
+    //     }
+    //   }
+    // });
     // app.Camera.on('flying.ended', ({ targetPano }) => {
     // })
     await app.TagManager.tag();
-    // init = false;
+
     tags$.value = '[xui_tags]';
 
-    app.TagManager.updatePosition(tags.value);
     if (app.config.mobile) {
       nextTick(() => {
         // let player = document.querySelector('.player')
@@ -170,9 +149,40 @@
     return changeUrl(url);
   };
 
-  const onClickHandler = () => {
-    // if (!isEdit.value && !positionInfo.value && isFixed.value) {
-    //   closeTag();
-    // }
+  const focusTag = (tag: tagType) => {
+    nextTick(async () => {
+      const app = await useApp();
+      let t = setTimeout(() => {
+        clearTimeout(t);
+        let tagBox = document.getElementById(`tagBox_${tag.sid}`);
+        let arrowBox = document.getElementById(`arrow_${tag.sid}`);
+        try {
+          let tagBox_w = tagBox ? tagBox.getBoundingClientRect().width : 0;
+          let tagBox_h = tagBox ? tagBox.getBoundingClientRect().height : 0;
+          let arrowBox_w = arrowBox ? arrowBox.getBoundingClientRect().width : 0;
+          let arrowBox_h = arrowBox ? arrowBox.getBoundingClientRect().height : 0;
+          let params = {
+            sid: tag.sid,
+            tagBox: {
+              width: tagBox_w,
+              height: tagBox_h,
+            },
+            arrowBox: {
+              width: arrowBox_w,
+              height: arrowBox_h,
+            },
+          };
+
+          let position = getApp().config.mobile ? 'center' : 'left';
+          app.TagManager.focus(params, 'board', position);
+        } catch (err) {}
+      }, 300);
+    });
   };
 </script>
+
+<style lang="scss">
+  [is-mobile] .ui-view-layout [xui_tags] .content .trans {
+    padding: 0;
+  }
+</style>

+ 24 - 69
src/components/hotspot/metas/metas-image.vue

@@ -1,21 +1,20 @@
 <!--  -->
 <template>
-  <!-- <div v-if="imageList.length > 0 && type == 'IMAGE'" class="pic-box"> -->
   <div
     class="pic-box"
     :class="{ show: viewer }"
     :style="metasHeight ? `height:${metasHeight}px;` : ''"
   >
     <div>
-      <div class="ctrl-btn left-btn" v-if="imageNum != 0" @click.stop="chengeImgae('pre')">
-        <ui-icon type="left"></ui-icon>
+      <div class="ctrl-btn left-btn" v-if="imageNum != 0" @click.stop="changeImage('pre')">
+        <!-- <ui-icon type="left"></ui-icon> -->
       </div>
       <div
         class="ctrl-btn right-btn"
         v-if="imageNum < imageList.length - 1"
-        @click.stop="chengeImgae('next')"
+        @click.stop="changeImage('next')"
       >
-        <ui-icon type="right"></ui-icon>
+        <!-- <ui-icon type="right"></ui-icon> -->
       </div>
     </div>
     <div class="over-box" ref="containerRef">
@@ -26,7 +25,7 @@
       >
         <!-- <div
                     @click="openScale(i.src)"
-                    :style="`transform:translateX(${100 * index}%);background-image:url(${common.changeUrl(i.src)});`"
+                    :style="`transform:translateX(${100 * index}%);background-image:url(${changeUrl(i.src)});`"
                     class="image-item"
                     v-for="(i, index) in imageList"
                 ></div> -->
@@ -34,49 +33,19 @@
           @click="openScale(i.src)"
           :style="`transform:translateX(${100 * index}%);`"
           class="image-item"
+          :key="i.sid"
           v-for="(i, index) in imageList"
         >
-          <img :id="`domImg${index}`" :src="common.changeUrl(i.src)" alt="" />
+          <img :id="`domImg${index}`" :src="changeUrl(i.src)" alt="" />
         </div>
 
         <!-- <div v-else :style="`transform:translateX(${100 * index}%);`" class="image-item" v-for="(i, index) in imageList">
-                    <img @error="filesError(index)" :src="common.changeUrl(i.src)" alt="" />
+                    <img @error="filesError(index)" :src="changeUrl(i.src)" alt="" />
                 </div> -->
       </div>
-      <ui-icon v-show="loading" class="loading-icon" type="_loading_"></ui-icon>
-
-      <div v-if="isEdit" class="del-btn" @click="delPic()">
-        <ui-icon type="del"></ui-icon>
-      </div>
-    </div>
-    <div class="continue" v-if="(!isEdit && imageList.length > 1) || isEdit">
-      <ui-input
-        v-if="imageList.length < customer[type].maxNum && isEdit"
-        type="file"
-        :placeholder="customer[type].uploadPlace"
-        :disable="customer[type].upload"
-        :scale="customer[type].scale"
-        :accept="customer[type].accept"
-        :multiple="customer[type].multiple"
-        :maxSize="customer[type].maxSize"
-        :maxLen="customer[type].maxNum"
-        :othPlaceholder="customer[type].othPlaceholder"
-        @update:modelValue="(data) => hanlderFiles(data)"
-      >
-        <template v-slot:replace>
-          <span class="continue-tips">{{ $t('tag.toolbox.continueAdd') }}</span>
-        </template>
-      </ui-input>
-      <span v-if="isEdit" class="pic-num">
-        <span class="cur">{{ imageList.length }}</span>
-        <span> / {{ customer[type].maxNum }}</span>
-      </span>
-      <span v-else class="pic-num">
-        <span class="cur">{{ imageNum + 1 }}</span>
-        <span><span>&nbsp;</span>/<span>&nbsp;</span></span>
-        <span>{{ imageList.length }}</span>
-      </span>
+      <!-- <ui-icon v-show="loading" class="loading-icon" type="_loading_"></ui-icon> -->
     </div>
+
     <!-- 移动端缩放 -->
     <!-- swiper新增后,此功能无用 -->
     <!-- <teleport to="body">
@@ -93,21 +62,18 @@
 
 <script setup lang="ts">
   import { onMounted, nextTick, ref, computed, defineProps, defineEmits } from 'vue';
-  import { useStore } from 'vuex';
-  import common from '@/utils/common';
-  import { custom } from '../constant.js';
-  const customer = custom();
-  import { getApp, useApp } from '@/app';
-  import { Dialog } from '@/global_components';
-  import { useI18n } from '../../../i18n';
-  const { t } = useI18n({ useScope: 'global' });
-  // import { zoomElement } from './scale/index.js'
-  // import Hammer from 'hammerjs' // 引用hammerjs
+  import { tagType } from '/@/store/modules/scene';
+  import { changeUrl } from '../common';
+  import { useApp } from '/@/hooks/userApp';
   const isMobile = ref(false);
-  const store = useStore();
+  // const store = useStore();
   const type = ref('image');
   const emit = defineEmits(['close']);
   const props = defineProps({
+    data: {
+      type: Object,
+      default: {} as any as tagType,
+    },
     metasHeight: {
       type: Number,
       default: null,
@@ -121,21 +87,14 @@
       default: false,
     },
   });
-  const isEdit = computed(() => store.getters['tag/isEdit']);
-  const hotData = computed(() => store.getters['tag/hotData']);
-  const topology = ref(null);
+
   const imageList = computed(() => {
-    return hotData.value.media.image;
+    return props.data.media.image;
   });
   const loading = ref(true);
   const imageNum = ref(0);
-  const delPic = () => {
-    store.commit('tag/delMetas', { index: imageNum.value, type: type.value });
-    if (imageNum.value > 0) {
-      imageNum.value--;
-    }
-  };
-  const chengeImgae = (type) => {
+
+  const changeImage = (type) => {
     if (type == 'pre') {
       imageNum.value--;
     } else {
@@ -166,10 +125,6 @@
         var index = i + picLength;
         list[index] = { src: URL.createObjectURL(data[i]), file: data[i] };
       } else {
-        Dialog.toast({
-          type: 'error',
-          content: `${t('limit.maxLengthFile', { length: customer['image'].maxNum })}`,
-        });
         break;
       }
     }
@@ -313,7 +268,7 @@
           });
         }
       };
-      img.src = common.changeUrl(imageList.value[0].src);
+      img.src = changeUrl(imageList.value[0].src);
       // if (imageList.value.length > 1) {
       //     //监听移动端手势
       //     if (props.scale) {
@@ -349,7 +304,7 @@
   };
   const openScale = (src) => {
     if (isMobile.value) {
-      zoomInImg.value = common.changeUrl(src);
+      zoomInImg.value = changeUrl(src);
 
       let img = new Image();
       img.onload = () => {

+ 23 - 90
src/components/hotspot/show-tag.vue

@@ -1,112 +1,45 @@
 <!--  -->
 <template>
-  <div class="show-tag" :id="`tagBox_${hotData.sid}`">
+  <div class="show-tag" :id="`tagBox_${tag.sid}`">
     <div class="tag-title">
       <h2>
-        {{ hotData.title }}
-        <ui-audio
-          v-if="hotData.type == 'audio' && audioInfo.length > 0"
+        {{ tag.title }}
+        <!-- <ui-audio
+          v-if="tag.type == 'audio' && audioInfo.length > 0"
           class="audio"
           ref="audio"
           :src="common.changeUrl(audioInfo[0].src)"
-        />
+        /> -->
       </h2>
     </div>
-    <div class="desc" v-if="hotData.content != ''">
-      <div class="text" v-html="hotData.content"></div>
+    <div class="desc" v-if="tag.content != ''">
+      <div class="text" v-html="tag.content"></div>
     </div>
     <div
       class="tag-metas"
       @click.stop="open"
-      :class="{ mask: hotData.type == 'link', nocursor: hotData.type == 'video' }"
-      v-if="hotData.media[hotData.type].length > 0 && hotData.type != 'audio'"
+      :class="{ mask: tag.type == 'link', nocursor: tag.type == 'video' }"
+      v-if="tag.media[tag.type].length > 0 && tag.type != 'audio'"
     >
-      <metasImage v-if="hotData.type == 'image'" />
-      <metasVideo v-if="hotData.type == 'video'" />
-      <metasWeb v-if="hotData.type == 'link'" />
+      <metasImage :data="tag" v-if="tag.type == 'image'" />
+      <!-- <metasImage v-if="tag.type == 'image'" />
+      <metasVideo v-if="tag.type == 'video'" />
+      <metasWeb v-if="tag.type == 'link'" /> -->
     </div>
-    <!-- <div class="edit-btn" v-if="routerName && routerName == 'tag' && !editModule">
-            <span @click="edit()"><ui-icon type="edit"></ui-icon> 修改</span>
-        </div> -->
   </div>
 </template>
 
-<script setup>
-  import {
-    reactive,
-    toRefs,
-    onBeforeMount,
-    onMounted,
-    ref,
-    watchEffect,
-    computed,
-    watch,
-    defineEmits,
-  } from 'vue';
-  import metasImage from './metas/metas-image';
-  import metasVideo from './metas/metas-video';
-  import metasAudio from './metas/metas-audio';
-  import metasWeb from './metas/metas-web';
-  import common from '@/utils/common';
-  import { useStore } from 'vuex';
-  import { useMusicPlayer } from '@/utils/sound';
-  const musicPlayer = useMusicPlayer();
-  const editModule = computed(() => store.getters['editModule']);
-  const store = useStore();
-  const emit = defineEmits(['open']);
-  const hotData = computed(() => {
-    let data = store.getters['tag/hotData'];
-    if (data.type == 'audio' || data.type == 'video') {
-      // musicPlayer.pause(true)
-      // console.log('1qwdq');
-      window.parent.postMessage(
-        {
-          source: 'qjkankan',
-          event: 'toggleBgmStatus',
-          params: {
-            status: false,
-          },
-        },
-        '*',
-      );
-    }
-    return data;
-  });
-
-  const audioInfo = computed(() => {
-    return hotData.value.media.audio;
-  });
-  const router = computed(() => store.getters['router']);
-  const routerName = computed(() => {
-    let name = router.value.name || null;
-    return name;
+<script setup lang="ts">
+  import metasImage from './metas/metas-image.vue';
+  import { onMounted } from 'vue';
+  import { tagType } from '/@/store/modules/scene';
+  defineProps({
+    tag: {
+      type: Object,
+      default: {} as any as tagType,
+    },
   });
-  const audio = ref(null);
-  watchEffect(() => {
-    if (audio.value) {
-      audio.value.play();
-    }
-  });
-  const open = () => {
-    if (hotData.value.type != 'video') {
-      emit('open');
-      window.parent.postMessage(
-        {
-          source: 'qjkankan',
-          event: 'toggleFdkkHotspot',
-          params: {
-            status: 'open',
-          },
-        },
-        '*',
-      );
-      console.log(111111);
-    }
-  };
-  // const edit = () => {
-  //     store.commit('tag/edit')
-  //     store.commit('tag/gotoTag', hotData.value)
-  // }
+  const open = () => {};
   onMounted(() => {});
 </script>
 <style lang="scss" scoped>

+ 5 - 1
src/hooks/userApp.ts

@@ -2,6 +2,7 @@
 
 import consola from 'consola';
 import { KanKanInstance } from '/#/sdk';
+import browser from '/@/utils/browser';
 
 const instance = (window as any).KanKan;
 let app: KanKanInstance;
@@ -40,7 +41,10 @@ export function createApp(options: appOptions): Promise<KanKanInstance> {
   const _app = new instance(options);
   deferred.resolve(_app);
   (window as any).__sdk = _app;
-  document.body.setAttribute('is-mobile', 'true');
+  if (browser.isMobile()) {
+    document.body.setAttribute('is-mobile', 'true');
+  }
+
   app = _app;
   return Promise.resolve(app);
 }

+ 1 - 1
src/store/modules/scene.ts

@@ -18,7 +18,7 @@ interface vector3Type {
   y: number;
   z: number;
 }
-interface tagType {
+export interface tagType {
   sid: string;
   x: number;
   y: number;