Browse Source

Merge branch 'dev' of http://face3d.4dage.com:7005/chenzhiguang/qjkankan_v1.1.1 into dev

tremble 2 năm trước cách đây
mục cha
commit
96e82ce683
26 tập tin đã thay đổi với 287 bổ sung294 xóa
  1. 13 2
      packages/qjkankan-editor/package-lock.json
  2. 2 1
      packages/qjkankan-editor/package.json
  3. 6 6
      packages/qjkankan-editor/src/api/index.js
  4. 68 7
      packages/qjkankan-editor/src/components/RichTextEditor.vue
  5. 4 4
      packages/qjkankan-editor/src/components/materialListInMaterialSelector.vue
  6. 8 8
      packages/qjkankan-editor/src/components/materialSelector.vue
  7. 2 2
      packages/qjkankan-editor/src/components/materialSelectorFromWork.vue
  8. 25 48
      packages/qjkankan-editor/src/directives/vTitleInEditor.js
  9. 25 48
      packages/qjkankan-editor/src/directives/vTitleInManageCenter.js
  10. 28 51
      packages/qjkankan-editor/src/directives/vTooltipInEditor.js
  11. 22 51
      packages/qjkankan-editor/src/directives/vTooltipInManageCenter.js
  12. 16 2
      packages/qjkankan-editor/src/framework/play/pano/index.vue
  13. 1 0
      packages/qjkankan-editor/src/lang/_en.json
  14. 1 0
      packages/qjkankan-editor/src/lang/_zh.json
  15. 7 7
      packages/qjkankan-editor/src/mixins/index.js
  16. 1 1
      packages/qjkankan-editor/src/pages/edit.js
  17. 2 1
      packages/qjkankan-editor/src/views/hotspot/EditPanel.vue
  18. 1 1
      packages/qjkankan-editor/src/views/hotspot/hotspotIconType/custom_image.vue
  19. 11 5
      packages/qjkankan-editor/src/views/hotspot/hotspotType/article.vue
  20. 23 2
      packages/qjkankan-editor/src/views/hotspot/hotspotType/phone.vue
  21. 4 5
      packages/qjkankan-editor/src/views/material/audio/index.vue
  22. 5 6
      packages/qjkankan-editor/src/views/material/image/index.vue
  23. 5 6
      packages/qjkankan-editor/src/views/material/pano/index.vue
  24. 0 24
      packages/qjkankan-editor/src/views/material/style.less
  25. 5 6
      packages/qjkankan-editor/src/views/material/video/index.vue
  26. 2 0
      packages/qjkankan-editor/vue.config.js

+ 13 - 2
packages/qjkankan-editor/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "@qjkankan/editor",
-  "version": "1.2.0",
+  "version": "1.2.20230130.1026",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "@qjkankan/editor",
-      "version": "1.2.0",
+      "version": "1.2.20230130.1026",
       "dependencies": {
         "@floating-ui/dom": "^0.5.4",
         "@wangeditor/editor-for-vue": "^1.0.2",
@@ -14,6 +14,7 @@
         "d3": "^7.8.0",
         "element-ui": "^2.15.1",
         "html2canvas": "^1.4.1",
+        "libphonenumber-js": "^1.10.19",
         "photoswipe": "^4.1.3",
         "quill": "^1.3.7",
         "swiper": "^5.3.8",
@@ -11178,6 +11179,11 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/libphonenumber-js": {
+      "version": "1.10.19",
+      "resolved": "https://registry.npmmirror.com/libphonenumber-js/-/libphonenumber-js-1.10.19.tgz",
+      "integrity": "sha512-MDZ1zLIkfSDZV5xBta3nuvbEOlsnKCPe4z5r3hyup/AXveevkl9A1eSWmLhd2FX4k7pJDe4MrLeQsux0HI/VWg=="
+    },
     "node_modules/lines-and-columns": {
       "version": "1.2.4",
       "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -30131,6 +30137,11 @@
         "type-check": "~0.3.2"
       }
     },
+    "libphonenumber-js": {
+      "version": "1.10.19",
+      "resolved": "https://registry.npmmirror.com/libphonenumber-js/-/libphonenumber-js-1.10.19.tgz",
+      "integrity": "sha512-MDZ1zLIkfSDZV5xBta3nuvbEOlsnKCPe4z5r3hyup/AXveevkl9A1eSWmLhd2FX4k7pJDe4MrLeQsux0HI/VWg=="
+    },
     "lines-and-columns": {
       "version": "1.2.4",
       "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz",

+ 2 - 1
packages/qjkankan-editor/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@qjkankan/editor",
-  "version": "1.2.0",
+  "version": "1.2.20230130.1026",
   "private": true,
   "scripts": {
     "serve": "vue-cli-service serve",
@@ -23,6 +23,7 @@
     "d3": "^7.8.0",
     "element-ui": "^2.15.1",
     "html2canvas": "^1.4.1",
+    "libphonenumber-js": "^1.10.19",
     "photoswipe": "^4.1.3",
     "quill": "^1.3.7",
     "swiper": "^5.3.8",

+ 6 - 6
packages/qjkankan-editor/src/api/index.js

@@ -120,7 +120,7 @@ export function getPanoInfo(data, ok, no) {
 /**
  * 获取三维场景列表(不应使用其搜索功能,因为无法全局搜索,而且无论搜的是什么词,指定文件夹中所有子文件夹都会被返回。
  */
-export function getSceneList(data, ok) {
+export function get3DSceneList(data, ok) {
   const {
     pathLevel2Id,
     folderId,
@@ -150,7 +150,7 @@ export function getSceneList(data, ok) {
     })
     return
   } else {
-    http.postJson(`${URL_FILL}/ucenter/user/scene/newList`, {
+    http.postJson(`/ucenter/user/scene/newList`, {
       cameraId: null,
       cameraType: null,
       endTime: "",
@@ -185,15 +185,15 @@ export function getSceneList(data, ok) {
 }
 
 /**
- * 获取三维场景列表(使用关键词搜索功能)
+ * 获取三维场景列表(使用关键词搜索功能,分别搜索看看和看见,两个结果合并后返回
  */
 
- export function searchInAllScenes(data, ok) {
+ export function searchInAll3DScenes(data, ok) {
   const {
     searchKey,
   } = data
   return Promise.all([
-    http.postJson(`${URL_FILL}/ucenter/user/scene/getOnlySceneList`, {
+    http.postJson(`/ucenter/user/scene/getOnlySceneList`, {
       cameraId: null,
       cameraType: null,
       endTime: "",
@@ -210,7 +210,7 @@ export function getSceneList(data, ok) {
       searchKey,
       startTime: "",
     }),
-    http.postJson(`${URL_FILL}/ucenter/user/scene/getOnlySceneList`, {
+    http.postJson(`/ucenter/user/scene/getOnlySceneList`, {
       cameraId: null,
       cameraType: null,
       endTime: "",

+ 68 - 7
packages/qjkankan-editor/src/components/RichTextEditor.vue

@@ -11,7 +11,7 @@
       v-model="html"
       :defaultConfig="editorConfig"
       :mode="mode"
-      @onCreated="onCreated"
+      @onCreated="onEditorCreated"
     />
     <div class="bottom-bar">
       <button 
@@ -27,15 +27,42 @@
         {{$i18n.t('common.ok')}}
       </button>
     </div>
+
+    <div class="dialog" style="z-index: 2000" v-if="isShowImageSelectionWindow">
+      <MaterialSelector
+        :title="$i18n.t('gather.select_material')"
+        @cancle="isShowImageSelectionWindow = false"
+        @submit="onSubmitFromImageMaterialSelector"
+        :selectableType="['image']"
+        :initialMaterialType="'image'"
+        :isMultiSelection="true"
+      />
+    </div>
+
+    <div class="dialog" style="z-index: 2000" v-if="isShowVideoSelectionWindow">
+      <MaterialSelector
+        :title="$i18n.t('gather.select_material')"
+        @cancle="isShowVideoSelectionWindow = false"
+        @submit="onSubmitFromVideoMaterialSelector"
+        :selectableType="['video']"
+        :initialMaterialType="'video'"
+        :isMultiSelection="true"
+      />
+    </div>
   </div>
 </template>
 
 <script>
 import Vue from 'vue'
 import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
+import MaterialSelector from "@/components/materialSelector.vue";
 
 export default Vue.extend({
-  components: { Editor, Toolbar },
+  components: {
+    Editor,
+    Toolbar,
+    MaterialSelector,
+  },
   props: {
     initialHtml: {
       type: String,
@@ -46,13 +73,34 @@ export default Vue.extend({
     return {
       editor: null,
       html: this.initialHtml,
-      toolbarConfig: { },
-      editorConfig: { placeholder: '' },
-      mode: 'default', // or 'simple'
+      toolbarConfig: {
+      },
+      editorConfig: {
+        placeholder: 'fdf',
+        MENU_CONF: {
+          uploadImage: {
+            customBrowseAndUpload: (insertFn) => {
+              this.isShowImageSelectionWindow = true
+              this.insertFn = insertFn
+            }
+          },
+          uploadVideo: {
+            customBrowseAndUpload: (insertFn) => {
+              this.isShowVideoSelectionWindow = true
+              this.insertFn = insertFn
+            }
+          },
+        },
+      },
+      mode: 'default', // or 'simple',
+
+      isShowImageSelectionWindow: false,
+      isShowVideoSelectionWindow: false,
+      insertFn: null,
     }
   },
   methods: {
-    onCreated(editor) {
+    onEditorCreated(editor) {
       this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
     },
     onClickOk() {
@@ -60,7 +108,20 @@ export default Vue.extend({
     },
     onClickCancel() {
       this.$emit('cancel')
-    }
+    },
+    onSubmitFromImageMaterialSelector(selected) {
+      this.isShowImageSelectionWindow = false
+      for (const selectedItem of selected) {
+        this.insertFn(selectedItem.icon, `[${this.$i18n.t('gather.image')}: ${selectedItem.name}]`)
+      }
+    },
+    onSubmitFromVideoMaterialSelector(selected) {
+      this.isShowVideoSelectionWindow = false
+      for (const selectedItem of selected) {
+        console.log(selectedItem);
+        this.insertFn(selectedItem.ossPath, selectedItem.ossPath + this.$videoImgOriginalSize)
+      }
+    },
   },
   mounted() {
   },

+ 4 - 4
packages/qjkankan-editor/src/components/materialListInMaterialSelector.vue

@@ -303,8 +303,8 @@
 <script>
 import {
   getMaterialList,
-  getSceneList,
-  searchInAllScenes,
+  get3DSceneList,
+  searchInAll3DScenes,
   uploadMaterial,
   checkUserSize,
 } from "@/api";
@@ -541,7 +541,7 @@ export default {
       let params = null
       if (this.materialType === '3D') {
         if (!this.searchKey) {
-          getListFn = getSceneList
+          getListFn = get3DSceneList
           params = {
             pathLevel2Id: this.folderPath[1]?.id,
             folderId: this.currentFolderId,
@@ -550,7 +550,7 @@ export default {
             searchKey: this.searchKey,
           }
         } else {
-          getListFn = searchInAllScenes
+          getListFn = searchInAll3DScenes
           params = {
             searchKey: this.searchKey
           }

+ 8 - 8
packages/qjkankan-editor/src/components/materialSelector.vue

@@ -107,7 +107,7 @@
         v-slot:materialUploadSuccessIcon="slotProps"
       >
         <img
-          :src="slotProps.uploadInfo.successInfo[slotProps.tableItemStructure.key] + (Number(slotProps.uploadInfo.fileSize) > 512 ? $imgsuffix : ``)"
+          :src="slotProps.uploadInfo.successInfo[slotProps.tableItemStructure.key] + $imgsuffix"
           alt=""
         />
       </template>
@@ -133,7 +133,7 @@
         v-slot:materialIcon="slotProps"
       >
         <img
-          :src="slotProps.materialInfo[slotProps.tableItemStructure.key] + (Number(slotProps.materialInfo.fileSize) > 512 ? $imgsuffix : ``)"
+          :src="slotProps.materialInfo[slotProps.tableItemStructure.key] + $imgsuffix"
           alt=""
         />
       </template>
@@ -169,7 +169,7 @@
         v-slot:materialUploadSuccessIcon="slotProps"
       >
         <img
-          :src="slotProps.uploadInfo.successInfo[slotProps.tableItemStructure.key] + (Number(slotProps.uploadInfo.fileSize) > 512 ? $imgsuffix : ``)"
+          :src="slotProps.uploadInfo.successInfo[slotProps.tableItemStructure.key] + $imgsuffix"
           alt=""
         />
       </template>
@@ -195,7 +195,7 @@
         v-slot:materialIcon="slotProps"
       >
         <img
-          :src="slotProps.materialInfo[slotProps.tableItemStructure.key] + (Number(slotProps.materialInfo.fileSize) > 512 ? $imgsuffix : ``)"
+          :src="slotProps.materialInfo[slotProps.tableItemStructure.key] + $imgsuffix"
           alt=""
         />
       </template>
@@ -300,7 +300,7 @@
         v-slot:materialUploadSuccessIcon="slotProps"
       >
         <img
-          :src="slotProps.uploadInfo.successInfo[slotProps.tableItemStructure.key] + (Number(slotProps.uploadInfo.fileSize) > 512 ? $imgsuffix : ``)"
+          :src="slotProps.uploadInfo.successInfo[slotProps.tableItemStructure.key]"
           alt=""
         />
       </template>
@@ -326,7 +326,7 @@
         v-slot:materialIcon="slotProps"
       >
         <img
-          :src="slotProps.materialInfo[slotProps.tableItemStructure.key] + (Number(slotProps.materialInfo.fileSize) > 512 ? $imgsuffix : ``)"
+          :src="slotProps.materialInfo[slotProps.tableItemStructure.key]"
           alt=""
         />
       </template>
@@ -354,7 +354,7 @@
         v-slot:materialIcon="slotProps"
       >
         <img
-          :src="slotProps.materialInfo[slotProps.tableItemStructure.key] + (Number(slotProps.materialInfo.fileSize) > 512 ? $imgsuffix : ``)"
+          :src="slotProps.materialInfo[slotProps.tableItemStructure.key] + $imgsuffix"
           alt=""
         />
       </template>
@@ -501,7 +501,7 @@ export default {
       }
     },
     videoMaterialItemCustomProcess(item) {
-      item.icon = process.env.VUE_APP_ORIGIN == 'aws' ? item.icon : (item.ossPath + '?x-oss-process=video/snapshot,t_0,f_jpg,w_89,h_50,m_fast,ar_auto')
+      item.icon = process.env.VUE_APP_ORIGIN == 'aws' ? item.icon : (item.ossPath + this.$videoImg)
     },
     onClickComfirm: debounce(function () {
       this.$emit('submit', this.select)

+ 2 - 2
packages/qjkankan-editor/src/components/materialSelectorFromWork.vue

@@ -51,7 +51,7 @@
           </span>
           <span class="table-data">
             <div class="list-img">
-              <img :src="item.icon + (Number(item.fileSize) > 512 ? $imgsuffix : ``)" alt="">
+              <img :src="item.icon + $imgsuffix" alt="">
             </div>
           </span>
           <span class="table-data">
@@ -97,7 +97,7 @@
           </span>
           <span class="table-data">
             <div class="list-img">
-              <img :src="item.icon + (Number(item.fileSize) > 512 ? $imgsuffix : ``)" alt="">
+              <img :src="item.icon + $imgsuffix" alt="">
             </div>
           </span>
           <span class="table-data">

+ 25 - 48
packages/qjkankan-editor/src/directives/vTitleInEditor.js

@@ -1,9 +1,20 @@
 import Vue from 'vue'
 
 let timerId = null
+let intervalId = null
 let isShowTitle = false
 let titleNode = null
 
+function removeTitle() {
+  if (!isShowTitle) {
+    clearTimeout(timerId)
+  } else {
+    isShowTitle = false
+    document.body.removeChild(titleNode)
+    clearInterval(intervalId)
+  }
+}
+
 Vue.directive('title', {
   bind: function (el, binding) {
     if (!binding.value) {
@@ -37,58 +48,24 @@ Vue.directive('title', {
           if (e.clientY + 18 + titleNode.offsetHeight > document.documentElement.clientHeight) {
             titleNode.style.top = document.documentElement.clientHeight - titleNode.offsetHeight + 'px'
           }
+
+          intervalId = setInterval(() => {
+            if (!document.contains(el)) {
+              removeTitle()
+            }
+          }, 300);
+          
         }, 500);
       }
     }, {
       passive: false,
     })
-    el.addEventListener('mouseleave', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('mousedown', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('keydown', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('scroll', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('dragover', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('dragleave', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
+
+    el.addEventListener('mouseleave', removeTitle)
+    el.addEventListener('mousedown', removeTitle)
+    el.addEventListener('keydown', removeTitle)
+    el.addEventListener('scroll', removeTitle)
+    el.addEventListener('dragover', removeTitle)
+    el.addEventListener('dragleave', removeTitle)
   },
 })

+ 25 - 48
packages/qjkankan-editor/src/directives/vTitleInManageCenter.js

@@ -1,9 +1,20 @@
 import Vue from 'vue'
 
 let timerId = null
+let intervalId = null
 let isShowTitle = false
 let titleNode = null
 
+function removeTitle() {
+  if (!isShowTitle) {
+    clearTimeout(timerId)
+  } else {
+    isShowTitle = false
+    document.body.removeChild(titleNode)
+    clearInterval(intervalId)
+  }
+}
+
 Vue.directive('title', {
   bind: function (el, binding) {
     if (!binding.value) {
@@ -36,58 +47,24 @@ Vue.directive('title', {
           if (e.clientY + 18 + titleNode.offsetHeight > document.documentElement.clientHeight) {
             titleNode.style.top = document.documentElement.clientHeight - titleNode.offsetHeight + 'px'
           }
+
+          intervalId = setInterval(() => {
+            if (!document.contains(el)) {
+              removeTitle()
+            }
+          }, 300);
+          
         }, 500);
       }
     }, {
       passive: false,
     })
-    el.addEventListener('mouseleave', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('mousedown', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('keydown', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('scroll', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('dragover', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
-    el.addEventListener('dragleave', function () {
-      if (!isShowTitle) {
-        clearTimeout(timerId)
-      } else {
-        isShowTitle = false
-        document.body.removeChild(titleNode)
-      }
-    })
+
+    el.addEventListener('mouseleave', removeTitle)
+    el.addEventListener('mousedown', removeTitle)
+    el.addEventListener('keydown', removeTitle)
+    el.addEventListener('scroll', removeTitle)
+    el.addEventListener('dragover', removeTitle)
+    el.addEventListener('dragleave', removeTitle)
   },
 })

+ 28 - 51
packages/qjkankan-editor/src/directives/vTooltipInEditor.js

@@ -1,12 +1,23 @@
 import Vue from 'vue'
 import {computePosition, offset, flip, shift, arrow} from '@floating-ui/dom';
- 
+
+let tooltipNode = null
+let intervalId = null
+
+function removeTooltip() {
+  try {
+    clearInterval(intervalId)
+    document.body.removeChild(tooltipNode)
+  } catch(e) {
+    console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
+  }
+}
+
 Vue.directive('tooltip', {
   bind: function (el, binding) {
     if (!binding.value) {
       return
     }
-    let tooltipNode = null
     el.addEventListener('mouseenter', function(e) {
       tooltipNode = document.createElement('div')
       tooltipNode.style.position = 'fixed'
@@ -70,58 +81,24 @@ Vue.directive('tooltip', {
           left: arrowX != null ? `${arrowX}px` : '',
           [staticSide]: '-6px',
         });
+      }).catch((err) => {
+        console.log('计算tooltip位置时出现异常,可能因为目标元素已经被卸载。')
       });
+
+      intervalId = setInterval(() => {
+        if (!document.contains(el)) {
+          removeTooltip()
+        }
+      }, 300);
     }, {
       passive: false,
     })
-    el.addEventListener('mouseleave', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('mousedown', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('keydown', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('scroll', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('dragstart', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('dragstart', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('dragleave', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
+    el.addEventListener('mouseleave', removeTooltip)
+    el.addEventListener('mousedown', removeTooltip)
+    el.addEventListener('keydown', removeTooltip)
+    el.addEventListener('scroll', removeTooltip)
+    el.addEventListener('dragstart', removeTooltip)
+    el.addEventListener('dragstart', removeTooltip)
+    el.addEventListener('dragleave', removeTooltip)
   },
 })

+ 22 - 51
packages/qjkankan-editor/src/directives/vTooltipInManageCenter.js

@@ -1,12 +1,23 @@
 import Vue from 'vue'
 import {computePosition, offset, flip, shift, arrow} from '@floating-ui/dom';
- 
+
+let tooltipNode = null
+let intervalId = null
+
+function removeTooltip() {
+  try {
+    clearInterval(intervalId)
+    document.body.removeChild(tooltipNode)
+  } catch(e) {
+    console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
+  }
+}
+
 Vue.directive('tooltip', {
   bind: function (el, binding) {
     if (!binding.value) {
       return
     }
-    let tooltipNode = null
     el.addEventListener('mouseenter', function(e) {
       tooltipNode = document.createElement('div')
       tooltipNode.style.position = 'fixed'
@@ -70,58 +81,18 @@ Vue.directive('tooltip', {
           left: arrowX != null ? `${arrowX}px` : '',
           [staticSide]: '-6px',
         });
+      }).catch((err) => {
+        console.log('计算tooltip位置时出现异常,可能因为目标元素已经被卸载。')
       });
     }, {
       passive: false,
     })
-    el.addEventListener('mouseleave', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('mousedown', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('keydown', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('scroll', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('dragstart', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('dragstart', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
-    el.addEventListener('dragleave', function () {
-      try {
-        document.body.removeChild(tooltipNode)
-      } catch(e) {
-        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
-      }
-    })
+    el.addEventListener('mouseleave', removeTooltip)
+    el.addEventListener('mousedown', removeTooltip)
+    el.addEventListener('keydown', removeTooltip)
+    el.addEventListener('scroll', removeTooltip)
+    el.addEventListener('dragstart', removeTooltip)
+    el.addEventListener('dragstart', removeTooltip)
+    el.addEventListener('dragleave', removeTooltip)
   },
 })

+ 16 - 2
packages/qjkankan-editor/src/framework/play/pano/index.vue

@@ -6,7 +6,7 @@
       id="iframe-4dkk"
       width=""
       v-if="currentScene.type === '4dkk'"
-      :src="`https://test.4dkankan.com/sp${currentScene.version === 'V3' ? 'c' : currentScene.version === 'V4' ? 'g' : 'c'}.html?m=${currentScene.sceneCode}&lang=${lang}`"
+      :src="`${locationOrigin}/sp${currentScene.version === 'V3' ? 'c' : currentScene.version === 'V4' ? 'g' : ''}.html?m=${currentScene.sceneCode}&lang=${lang}`"
       frameborder="0"
     />
 
@@ -29,7 +29,10 @@ 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";
+import {
+  uploadCover,
+  searchInAll3DScenes,
+} from "@/api";
 import config from '@/config'
 
 let __krfn = krfn.default;
@@ -41,6 +44,7 @@ export default {
       showFlash: false,
       inter: null,
       lang: config.lang || 'zh',
+      locationOrigin: process.env.VUE_APP_PROXY_URL_ROOT,
     }
   },
   computed: {
@@ -69,6 +73,16 @@ export default {
       }
       if (newVal.type == '4dkk') {
         $("#pano").empty();
+        if (!newVal.version) { // v1.3之前在作品中新增的三维场景,没有version这个值,需要查询。
+          searchInAll3DScenes({
+            searchKey: newVal.sceneTitle,
+          }, (res) => {
+            const originItem = res.data.list.find((item) => {
+              return item.num === newVal.sceneCode
+            })
+            newVal.version = originItem.buildType
+          })
+        }
         return
       } else {
         $("#pano").empty();

+ 1 - 0
packages/qjkankan-editor/src/lang/_en.json

@@ -908,6 +908,7 @@
     "text_content": "文字内容",
     "apply_to_all": "应用到所有",
     "phone_placeholder": "请输入电话号码",
+    "phone_error_tip": "请输入正确的电话号码",
     "select_pdf": "添加PDF",
     "change_pdf": "更换PDF",
     "pdf_invalid_tip": "请选择50MB以内、PDF格式的文件",

+ 1 - 0
packages/qjkankan-editor/src/lang/_zh.json

@@ -912,6 +912,7 @@
     "text_content": "文字内容",
     "apply_to_all": "应用到所有",
     "phone_placeholder": "请输入电话号码",
+    "phone_error_tip": "请输入正确的电话号码",
     "select_pdf": "添加PDF",
     "change_pdf": "更换PDF",
     "pdf_invalid_tip": "请选择50MB以内、PDF格式的文件",

+ 7 - 7
packages/qjkankan-editor/src/mixins/index.js

@@ -84,15 +84,15 @@ Vue.prototype.$msg.error = (string)=>{
   });
 }
 
-Vue.prototype.$videoImg =
-  "?x-oss-process=video/snapshot,t_0,f_jpg,w_0,h_0,m_fast,ar_auto";
+Vue.prototype.$videoImg = "?x-oss-process=video/snapshot,t_0,f_jpg,w_100,m_fast,ar_auto";
 
-  
-Vue.prototype.$imgsuffix =
-process.env.VUE_APP_ORIGIN=='aws'?encodeURIComponent('?x-oss-process=image@resize,m_lfit,w_200@crop,w_200,h_200'.replaceAll('/','@'))
-:`?x-oss-process=image/resize,p_20&${Math.random()}`;
+Vue.prototype.$videoImgOriginalSize = "?x-oss-process=video/snapshot,t_0,f_jpg,m_fast,ar_auto";
 
-console.log(process.env.VUE_APP_ORIGIN);
+Vue.prototype.$imgsuffix = '?x-oss-process=image/resize,m_lfit,w_200/crop,w_200,h_200'
+
+Vue.prototype.$getImgResizeSuffix = function(width, height) {
+  return `?x-oss-process=image/resize,m_lfit,w_${width},h_${height},limit_0`;
+}
 
 Vue.prototype.$scrollbars = [];
 

+ 1 - 1
packages/qjkankan-editor/src/pages/edit.js

@@ -9,7 +9,7 @@ import '@/directives/vTitleInEditor.js'
 import '@/directives/vTooltipInEditor.js'
 import { i18n } from "@/lang"
 
-console.log('v1014.1550');
+console.log(`version: ${process.env.VUE_APP_VERSION}`)
 
 // 热点图标默认大小
 window.g_hotspotCurrentScale = 1

+ 2 - 1
packages/qjkankan-editor/src/views/hotspot/EditPanel.vue

@@ -164,6 +164,7 @@ import Switcher from "@/components/shared/Switcher.vue";
 import TabbarSwitcher from "@/components/shared/TabbarSwitcher.vue";
 import TabbarSwitcherIcon from "@/components/shared/TabbarSwitcherIcon.vue";
 import hotspotTypeList from "./hotspotTypeList.js";
+import { isValidPhoneNumber } from 'libphonenumber-js/max'
 
 export default {
   props: ['show', 'data', 'editTitle'],
@@ -335,7 +336,7 @@ export default {
           }
           break;
         case 'phone':
-          if (!this.hotspot.phoneInfo.phone) {
+          if (!isValidPhoneNumber(this.hotspot.phoneInfo.phone) && !isValidPhoneNumber('+86' + this.hotspot.phoneInfo.phone)) {
             return false
           }
           break;

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

@@ -57,7 +57,7 @@ export default {
   methods: {
     handleSubmitFromMaterialSelector(data) {
       this.isShowSelectionWindow = false
-      this.hotspot.customIconInfo.img = data[0].icon
+      this.hotspot.customIconInfo.img = data[0].icon + this.$getImgResizeSuffix(300, 300)
     },
     onClickDelete() {
       this.hotspot.customIconInfo.img = ''

+ 11 - 5
packages/qjkankan-editor/src/views/hotspot/hotspotType/article.vue

@@ -71,11 +71,17 @@ export default {
     }
   }
 
-  .rich-text-editor {
-    position: absolute;
-    left: 50%;
-    top: 50%;
-    transform: translate(-50%, -50%);
+  .dialog {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    .rich-text-editor {
+      flex: 0 0 auto;
+      width: 65%;
+      &.w-e-full-screen-container {
+        transform: initial !important;
+      }
+    }
   }
 }
 </style>

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

@@ -2,8 +2,11 @@
   <div class="phone-effect-setting">
     <div class="phone-input-wrapper">
       <input
-        v-model.trim="hotspot.phoneInfo.phone"
-        type="text"
+        ref="input"
+        :value="hotspot.phoneInfo.phone"
+        @input="onInput"
+        @blur="onInputBlur"
+        type="tel"
         :placeholder="$i18n.t('hotspot.phone_placeholder')"
       />
       <!-- <span class="count">{{ hotspot.hotspotTitle.length }}/15</span> -->
@@ -13,13 +16,31 @@
 
 <script>
 import { mapGetters } from "vuex";
+import { isValidPhoneNumber } from 'libphonenumber-js/max'
 
 export default {
+  data() {
+    return {
+    }
+  },
   computed: {
     ...mapGetters({
       hotspot: 'hotspot',
     }),
   },
+  methods: {
+    onInput(e) {
+      this.hotspot.phoneInfo.phone = this.$refs.input.value
+    },
+    onInputBlur() {
+      if (!isValidPhoneNumber(this.hotspot.phoneInfo.phone) && !isValidPhoneNumber('+86' + this.hotspot.phoneInfo.phone)) {
+        this.$msg({
+          message: this.$i18n.t('hotspot.phone_error_tip'),
+          type: 'error'
+        })
+      }
+    }
+  },
 }
 </script>
 

+ 4 - 5
packages/qjkankan-editor/src/views/material/audio/index.vue

@@ -18,11 +18,10 @@
             class="ui-button submit"
           >
             <span>{{upload_material}}</span>
-            <i class="iconfont icon-material_prompt hover-tips hover-tips-upload-icon">
-              <div>
-                <div class="remark">{{audio_size}}</div>
-              </div>
-            </i>
+            <i
+              class="iconfont icon-material_prompt"
+              v-tooltip="audio_size"
+            />
             <upload
               ref="uploadFile"
               :failString="audio_fail"

+ 5 - 6
packages/qjkankan-editor/src/views/material/image/index.vue

@@ -18,11 +18,10 @@
             class="ui-button submit"
           >
             <span>{{upload_material}}</span>
-            <i class="iconfont icon-material_prompt hover-tips hover-tips-upload-icon">
-              <div>
-                <div class="remark">{{img_size}}</div>
-              </div>
-            </i>
+            <i
+              class="iconfont icon-material_prompt"
+              v-tooltip="img_size"
+            />
             <upload
               ref="uploadFile"
               :failString="img_fail"
@@ -109,7 +108,7 @@
           >
             <img
               :id="'img' + lineData.id"
-              :src="lineData.type === 'dir' ? require('@/assets/images/icons/folder-blue.png') : itemData + (Number(lineData.fileSize)>512 ? $imgsuffix : '') "
+              :src="lineData.type === 'dir' ? require('@/assets/images/icons/folder-blue.png') : itemData + $imgsuffix"
               alt=""
               @click="lineData.type === 'dir' ? onClickFolder(lineData) : previewImage(lineData)"
             />

+ 5 - 6
packages/qjkankan-editor/src/views/material/pano/index.vue

@@ -14,11 +14,10 @@
         <div class="btn">
           <button @mouseover.stop="showList = true" @click="onUploadFile" class="ui-button submit">
             <span>{{ upload_material }}</span>
-            <i class="iconfont icon-material_prompt hover-tips hover-tips-upload-icon">
-              <div>
-                <div class="remark">{{ pano_size }}</div>
-              </div>
-            </i>
+            <i
+              class="iconfont icon-material_prompt"
+              v-tooltip="pano_size"
+            />
             <upload ref="uploadFile" :failString="pano_fail" :limitFailStr="pano_limit" accept-type=".jpg"
               media-type="image" :limit="120" @file-change="onFileChange"></upload>
           </button>
@@ -102,7 +101,7 @@
             class="img"
             @click="previewImage(lineData)"
           >
-            <img :src="itemData + (Number(lineData.fileSize) > 512 ? $imgsuffix : '')"
+            <img :src="itemData + $imgsuffix"
               alt="" />
           </div>
           <div

+ 0 - 24
packages/qjkankan-editor/src/views/material/style.less

@@ -359,30 +359,6 @@
   padding: 0 16px;
 }
 
-// 左上角上传素材按钮的提示icon,hover时的样式和一般的有tooltip的元素不一样
-.hover-tips.hover-tips-upload-icon {
-  &:hover {
-    color: #fff !important;
-    cursor: default;
-  }
-  // tip的方框
-  > div {
-    top: -30px;
-    left: -30px;
-    transform: translateX(0);
-    // tip的箭头
-    &::before {
-      position: absolute;
-      bottom: -14px;
-      transform: translateX(0);
-      left: 30px;
-    }
-    .remark {
-      line-height: 20px;
-    }
-  }
-}
-
 input::placeholder,
 textarea::placeholder {
   font-size: 14px;

+ 5 - 6
packages/qjkankan-editor/src/views/material/video/index.vue

@@ -18,11 +18,10 @@
             class="ui-button submit"
           >
             <span>{{upload_material}}</span>
-            <i class="iconfont icon-material_prompt hover-tips hover-tips-upload-icon">
-              <div>
-                <div class="remark">{{video_size}}</div>
-              </div>
-            </i>
+            <i
+              class="iconfont icon-material_prompt"
+              v-tooltip="video_size"
+            />
             <upload
               ref="uploadFile"
               :failString="video_limit"
@@ -573,7 +572,7 @@ export default {
             if (i.type !== 'dir') {
               i.fileSize = changeByteUnit(Number(i.fileSize));
             }
-            i.icon = process.env.VUE_APP_ORIGIN=='aws'?i.icon:(i.ossPath + '?x-oss-process=video/snapshot,t_0,f_jpg,w_89,h_50,m_fast,ar_auto');
+            i.icon = process.env.VUE_APP_ORIGIN=='aws' ? i.icon : (i.ossPath + this.$videoImg);
             return i;
           });
           this.list = this.list.concat(newData)

+ 2 - 0
packages/qjkankan-editor/vue.config.js

@@ -1,5 +1,7 @@
 const proxy_url = process.env.VUE_APP_PROXY_URL
 
+process.env.VUE_APP_VERSION = require('./package.json').version
+
 let pages = {
   edit: 'src/pages/edit.js',
   // show: 'src/pages/show.js',