瀏覽代碼

去除define导入语法糖

bill 3 年之前
父節點
當前提交
ba08a78144
共有 48 個文件被更改,包括 507 次插入235 次删除
  1. 1 1
      src/api/fuse-model.ts
  2. 23 30
      src/api/view.ts
  3. 1 1
      src/components/bill-ui/assets/scss/editor/_toolbox.scss
  4. 1 1
      src/components/bill-ui/components/audio/index.vue
  5. 1 1
      src/components/bill-ui/components/button/index.vue
  6. 1 1
      src/components/bill-ui/components/cropper/cropper.vue
  7. 1 1
      src/components/bill-ui/components/floating/index.vue
  8. 0 1
      src/components/bill-ui/components/gate/layer.vue
  9. 1 1
      src/components/bill-ui/components/icon/index.vue
  10. 0 1
      src/components/bill-ui/components/input/check-radio.vue
  11. 0 1
      src/components/bill-ui/components/input/checkbox.vue
  12. 1 1
      src/components/bill-ui/components/input/color.vue
  13. 1 1
      src/components/bill-ui/components/input/file.vue
  14. 1 1
      src/components/bill-ui/components/input/number.vue
  15. 0 1
      src/components/bill-ui/components/input/radio.vue
  16. 1 1
      src/components/bill-ui/components/input/range.vue
  17. 1 1
      src/components/bill-ui/components/input/richtext.vue
  18. 1 1
      src/components/bill-ui/components/input/search.vue
  19. 1 1
      src/components/bill-ui/components/input/select.vue
  20. 0 1
      src/components/bill-ui/components/input/switch.vue
  21. 1 1
      src/components/bill-ui/components/input/text.vue
  22. 0 3
      src/components/bill-ui/components/input/textarea.vue
  23. 0 1
      src/components/bill-ui/components/loading/Loading.vue
  24. 1 1
      src/components/bill-ui/components/menu-item/index.vue
  25. 1 1
      src/components/bill-ui/components/message/message.vue
  26. 1 1
      src/components/bill-ui/components/size-animation/index.vue
  27. 1 1
      src/components/bill-ui/components/slide/index.vue
  28. 1 1
      src/components/bill-ui/components/tip/index.vue
  29. 1 1
      src/components/bill-ui/components/tree/index.vue
  30. 1 1
      src/components/list/index.vue
  31. 0 1
      src/components/menu/menu-item-child.vue
  32. 1 1
      src/components/menu/menu-item.vue
  33. 0 1
      src/env/index.ts
  34. 5 3
      src/layout/edit/fuse-edit.vue
  35. 4 10
      src/layout/edit/scene-edit.vue
  36. 1 3
      src/layout/main.vue
  37. 0 83
      src/layout/model/index.vue
  38. 12 10
      src/layout/scene-list/index.vue
  39. 100 0
      src/model/app.vue
  40. 63 0
      src/model/index.ts
  41. 160 0
      src/model/platform.ts
  42. 47 9
      src/store/view.ts
  43. 1 0
      src/utils/index.ts
  44. 28 3
      src/views/view/index.vue
  45. 29 44
      src/views/view/sign.vue
  46. 2 0
      src/views/view/style.scss
  47. 3 1
      tsconfig.json
  48. 6 5
      vite.config.ts

+ 1 - 1
src/api/fuse-model.ts

@@ -64,7 +64,7 @@ const serviceToLocal = (serviceModel: ServiceFuseModel): FuseModel => ({
 })
 
 const localToService = (model: FuseModel): Omit<ServiceFuseModel, 'sceneData'> => ({
-  fusionId: Number(model.id),
+  fusionId: model.fusionId,
   hide: Number(!model.show),
   opacity: model.opacity,
   fusionNumId: model.fusionNumId,

+ 23 - 30
src/api/view.ts

@@ -10,7 +10,7 @@ export type View = {
   title: string
   sort: number
   flyData: string,
-} & ({ fusionId: number } | { num: string, numType: Scene['type'] })
+} & ({ fusionId: number, num: null, numType: null } | { fusionId: null, num: string, numType: Scene['type'] })
 
 type ServiceView = {
   viewId: number
@@ -18,37 +18,29 @@ type ServiceView = {
   viewPoint:	string	
   viewImg:	string	
   sort:	number	
-} & ({ fusionId: number } | { num: string, numType: Scene['type'] })
+} & ({ fusionId: string, num: null, numType: null } | { fusionId: null, num: string, numType: Scene['type'] })
 
-const toLocal = (serviceView: ServiceView) : View => {
-  const base = {
-    id: serviceView.viewId.toString(),
-    cover: serviceView.viewImg,
-    title: serviceView.viewTitle,
-    sort: serviceView.sort,
-    flyData: JSON.parse(serviceView.viewPoint),
-  }
-  if ('fusionId' in serviceView) {
-    return { ...base, fusionId: serviceView.fusionId }
-  } else {
-    return { ...base, num: serviceView.num, numType: serviceView.numType }
-  }
-}
+const toLocal = (serviceView: ServiceView) : View => ({
+  id: serviceView.viewId.toString(),
+  cover: serviceView.viewImg,
+  title: serviceView.viewTitle,
+  sort: serviceView.sort,
+  flyData: JSON.parse(serviceView.viewPoint),
+  num: serviceView.num, 
+  numType: serviceView.numType,
+  fusionId: serviceView.fusionId ? Number(serviceView.fusionId) : null
+} as View)
 
-const toService = (view: View, isUpdate = true): PartialProps<ServiceView, 'viewId'> => {
-  const base = {
-    viewId: isUpdate ? Number(view.id) : undefined,
-    viewTitle: view.title,	
-    viewPoint: JSON.stringify(view.flyData),
-    viewImg: view.cover,
-    sort:	view.sort,
-  }
-  if ('fusionId' in view) {
-    return { ...base, fusionId: view.fusionId } as ServiceView
-  } else {
-    return { ...base, num: view.num, numType: view.numType } as ServiceView
-  }
-}
+const toService = (view: View, isUpdate = true): PartialProps<ServiceView, 'viewId'> => ({
+  viewId: isUpdate ? Number(view.id) : undefined,
+  viewTitle: view.title,	
+  viewPoint: JSON.stringify(view.flyData),
+  viewImg: view.cover,
+  sort:	view.sort,
+  num: view.num, 
+  numType: view.numType,
+  fusionId: view.fusionId ? view.fusionId.toString() : null
+})
 
 export type Views = View[]
 
@@ -58,6 +50,7 @@ export const fetchViews = async () => {
 }
 
 export const postAddView = async (view: View) => {
+  console.log(view, { ...toService(view, false), caseId: params.caseId })
   const serviceView = await axios.post<ServiceView>(INSERT_VIEW, { ...toService(view, false), caseId: params.caseId })
   return toLocal(serviceView)
 }

+ 1 - 1
src/components/bill-ui/assets/scss/editor/_toolbox.scss

@@ -2,7 +2,7 @@
 
 .ui-editor-toolbox {
     position: absolute;
-    z-index: 1;
+    z-index: 2;
     right: var(--editor-menu-right);
     padding: 20px;
     width:  var(--editor-toolbox-width);;

+ 1 - 1
src/components/bill-ui/components/audio/index.vue

@@ -8,7 +8,7 @@
 </template>
 
 <script setup>
-import { defineProps, ref, watchEffect, defineExpose } from 'vue'
+import { ref, watchEffect } from 'vue'
 defineProps({
     src: String,
 })

+ 1 - 1
src/components/bill-ui/components/button/index.vue

@@ -9,7 +9,7 @@
 
 
 <script setup>
-import { defineProps, computed } from 'vue'
+import { computed } from 'vue'
 import { normalizeUnitToStyle } from '../../utils/index'
 import UIIcon from '../icon/index.vue'
 

+ 1 - 1
src/components/bill-ui/components/cropper/cropper.vue

@@ -14,7 +14,7 @@
 <script setup>
 import { VueCropper } from 'vue-cropper'
 import Confirm from '../dialog/Confirm.vue'
-import { computed, defineProps, ref } from 'vue'
+import { computed, ref } from 'vue'
 import 'vue-cropper/dist/index.css'
 
 const layerWidth = 500

+ 1 - 1
src/components/bill-ui/components/floating/index.vue

@@ -7,7 +7,7 @@
 </template>
 
 <script setup>
-import { defineProps, defineExpose, onUnmounted, reactive, watch, computed, onUpdated, onActivated, ref, watchEffect } from 'vue'
+import { onUnmounted, reactive, watch, computed, onUpdated, onActivated, ref, watchEffect } from 'vue'
 import { getPostionByTarget, getScrollParents, getZIndex } from '../../utils'
 
 const Horizontal = {

+ 0 - 1
src/components/bill-ui/components/gate/layer.vue

@@ -15,7 +15,6 @@
 <script setup>
 import { 
   ref, 
-  defineProps,
   watchEffect,
   computed,
   provide,

+ 1 - 1
src/components/bill-ui/components/icon/index.vue

@@ -10,7 +10,7 @@
 </template>
 
 <script setup>
-import { defineProps, computed, defineEmits, ref, reactive, defineExpose } from 'vue'
+import { computed, ref, reactive } from 'vue'
 import { normalizeUnitToStyle, os } from '../../utils'
 import Icon from './icon/index.vue'
 import Tip from '../tip'

+ 0 - 1
src/components/bill-ui/components/input/check-radio.vue

@@ -23,7 +23,6 @@
 import icon from '../icon'
 import { checkboxPropsDesc } from './state'
 import { randomId } from '../../utils'
-import { defineProps, defineEmits } from 'vue'
 const props = defineProps(checkboxPropsDesc)
 const emit = defineEmits(['update:modelValue'])
 const id = randomId(4)

+ 0 - 1
src/components/bill-ui/components/input/checkbox.vue

@@ -14,7 +14,6 @@
 import icon from '../icon'
 import { checkboxPropsDesc } from './state'
 import { randomId } from '../../utils'
-import { defineProps, defineEmits } from 'vue'
 const props = defineProps(checkboxPropsDesc)
 const emit = defineEmits(['update:modelValue'])
 const id = randomId(4)

+ 1 - 1
src/components/bill-ui/components/input/color.vue

@@ -10,7 +10,7 @@
 <script setup>
 import { colorPropsDesc } from './state'
 import { randomId } from '../../utils'
-import { defineProps, defineEmits, nextTick } from 'vue'
+import { nextTick } from 'vue'
 const props = defineProps(colorPropsDesc)
 const emit = defineEmits(['update:modelValue'])
 const id = randomId(4)

+ 1 - 1
src/components/bill-ui/components/input/file.vue

@@ -40,7 +40,7 @@
 import { filePropsDesc } from './state'
 import { toRawType } from '../../utils'
 import Message from '../message'
-import { defineProps, defineEmits, defineExpose, ref, computed } from 'vue'
+import { ref, computed } from 'vue'
 
 const props = defineProps({
     ...filePropsDesc,

+ 1 - 1
src/components/bill-ui/components/input/number.vue

@@ -27,7 +27,7 @@
 <script setup>
 import UIText from './text'
 import { numberPropsDesc } from './state'
-import { defineProps, defineEmits, computed, watchEffect, ref } from 'vue'
+import { computed, watchEffect, ref } from 'vue'
 import { toRawType } from '../../utils'
 import Icon from '../icon'
 

+ 0 - 1
src/components/bill-ui/components/input/radio.vue

@@ -21,7 +21,6 @@
 import Icon from '../icon'
 import { radioPropsDesc } from './state'
 import { randomId } from '../../utils'
-import { defineProps, defineEmits } from 'vue'
 const props = defineProps(radioPropsDesc)
 const emit = defineEmits(['update:modelValue'])
 const id = randomId(4)

+ 1 - 1
src/components/bill-ui/components/input/range.vue

@@ -23,7 +23,7 @@
 </template>
 
 <script setup>
-import { ref, computed, onMounted, defineProps, watchEffect } from 'vue'
+import { ref, computed, onMounted, watchEffect } from 'vue'
 import { rangePropsDesc } from './state'
 import UInumber from './number.vue'
 import { os } from '../../utils/index'

+ 1 - 1
src/components/bill-ui/components/input/richtext.vue

@@ -27,7 +27,7 @@
 
 <script setup>
 import { richtextPropsDesc } from './state'
-import { defineProps, defineEmits, defineExpose, nextTick, ref, watchEffect } from 'vue'
+import { nextTick, ref, watchEffect } from 'vue'
 const props = defineProps({
     ...richtextPropsDesc,
 })

+ 1 - 1
src/components/bill-ui/components/input/search.vue

@@ -13,7 +13,7 @@
 </template>
 
 <script setup>
-import { ref, watchEffect, defineEmits, onUnmounted } from 'vue'
+import { ref, watchEffect, onUnmounted } from 'vue'
 import { searchPropsDesc, textEmitsDesc } from './state'
 import UISelect from './select.vue'
 

+ 1 - 1
src/components/bill-ui/components/input/select.vue

@@ -63,7 +63,7 @@
 <script setup>
 import UItext from './text.vue'
 import UIFloating from '../floating/index.vue'
-import { ref, onUnmounted, computed, defineExpose, watchEffect } from 'vue'
+import { ref, onUnmounted, computed, watchEffect } from 'vue'
 import { selectPropsDesc, selectEmitsDesc } from './state'
 import icon from '../icon'
 

+ 0 - 1
src/components/bill-ui/components/input/switch.vue

@@ -15,7 +15,6 @@
 <script setup>
 import { switchPropsDesc } from './state'
 import { randomId } from '../../utils'
-import { defineProps, defineEmits } from 'vue'
 const props = defineProps(switchPropsDesc)
 const emit = defineEmits(['update:modelValue'])
 const id = randomId(4)

+ 1 - 1
src/components/bill-ui/components/input/text.vue

@@ -40,7 +40,7 @@
 
 <script setup>
 import { textEmitsDesc, textPropsDesc } from './state'
-import { defineProps, defineEmits, defineExpose, nextTick, ref } from 'vue'
+import { nextTick, ref } from 'vue'
 const props = defineProps({
     type: {
         type: String,

+ 0 - 3
src/components/bill-ui/components/input/textarea.vue

@@ -30,9 +30,6 @@
 <script setup>
 import { textareaPropsDesc } from './state'
 import { 
-  defineProps, 
-  defineEmits, 
-  defineExpose,
   nextTick,
   ref
 } from 'vue'

+ 0 - 1
src/components/bill-ui/components/loading/Loading.vue

@@ -12,7 +12,6 @@
     </teleport>
 </template>
 <script setup>
-import { defineProps } from 'vue'
 import getZIndex from '../../utils/zindex'
 
 defineProps({

+ 1 - 1
src/components/bill-ui/components/menu-item/index.vue

@@ -14,7 +14,7 @@
 
 <script setup>
 import UIIcon from '../icon'
-import { defineProps, defineExpose, defineEmits, ref } from 'vue'
+import { ref } from 'vue'
 
 const self = ref(null)
 const props = defineProps({

+ 1 - 1
src/components/bill-ui/components/message/message.vue

@@ -18,7 +18,7 @@
 <script setup>
 import uiIcon from '../icon'
 import getZindex from '../../utils/zindex'
-import { defineProps, onMounted, ref, nextTick } from 'vue'
+import { onMounted, ref, nextTick } from 'vue'
 
 const props = defineProps({
   msg: {

+ 1 - 1
src/components/bill-ui/components/size-animation/index.vue

@@ -6,7 +6,7 @@
 
 <script setup>
 import { changeWHFactory } from '../../utils'
-import { defineExpose, ref, watchEffect, defineProps } from 'vue'
+import { ref, watchEffect } from 'vue'
 
 const props = defineProps({
     attr: {

+ 1 - 1
src/components/bill-ui/components/slide/index.vue

@@ -21,7 +21,7 @@
 
 <script setup>
 import { Gate, GateContent } from '../gate'
-import { defineProps, ref, watchEffect, computed } from 'vue'
+import { ref, watchEffect, computed } from 'vue'
 import UIIcon from '../icon'
 import { nextTick } from 'vue';
 

+ 1 - 1
src/components/bill-ui/components/tip/index.vue

@@ -6,7 +6,7 @@
 </template>
 
 <script setup>
-import { defineProps, computed, defineEmits } from 'vue'
+import { computed } from 'vue'
 import { os } from '../../utils'
 
 const props = defineProps({

+ 1 - 1
src/components/bill-ui/components/tree/index.vue

@@ -36,7 +36,7 @@
 export default { name: 'ui-tree' }
 </script>
 <script setup>
-import { defineProps, ref, computed, watch, onDeactivated, onActivated, watchEffect } from 'vue'
+import { ref, computed, watch, onDeactivated, onActivated, watchEffect } from 'vue'
 import UISizeAnimation from '../size-animation'
 import { inRevise } from '../../utils'
 

+ 1 - 1
src/components/list/index.vue

@@ -11,7 +11,7 @@
         v-for="(item, i) in data" 
         :key="key ? item[key] : i" 
         :class="{select: item.select}"
-        @click="$emit('changeSelect', item)"
+        @click.stop="$emit('changeSelect', item)"
       >
         <div class="atom-content">
           <slot name="atom" :item="item"></slot>

+ 0 - 1
src/components/menu/menu-item-child.vue

@@ -23,7 +23,6 @@
 </template>
 
 <script setup lang="ts">
-import { defineProps, defineEmits } from 'vue'
 import MenuChild from './menu-item.vue'
 
 import type { Item, Items } from './index.vue'

+ 1 - 1
src/components/menu/menu-item.vue

@@ -45,7 +45,7 @@
 
 <script setup lang="ts">
 import MenuChildItem from './menu-item-child.vue'
-import { defineProps, defineEmits, computed, ref } from 'vue'
+import { computed, ref } from 'vue'
 
 import type { Item, Items } from './index.vue'
 

+ 0 - 1
src/env/index.ts

@@ -18,7 +18,6 @@ export const currentModelStack = stackFactory(ref<FuseModel | null>(null))
 export const showModelsMapStack = stackFactory(ref<Map<FuseModel, boolean>>(new Map))
 export const modelsChangeStoreStack = stackFactory(ref<boolean>(false))
 export const showTaggingPositionsStack = stackFactory(ref<WeakSet<TaggingPosition>>(new WeakSet()))
-// export const showModelsChangeStoreStack = stackFactory
 
 export const custom = flatStacksValue({
   viewMode: viewModeStack,

+ 5 - 3
src/layout/edit/fuse-edit.vue

@@ -1,6 +1,5 @@
 <template>
   <template v-if="loaded" style="height: 100%">
-    <Model :type="FUSE" />
     <Header></Header>
     <router-view v-slot="{ Component }">
       <keep-alive>
@@ -15,7 +14,7 @@ import { ref, watch } from 'vue'
 import { currentMeta, router } from '@/router'
 import { showLeftPanoStack, showRightPanoStack } from '@/env'
 import { togetherCallback } from '@/utils'
-import { Model, FUSE } from '../model/index.vue'
+import { loadModel, fuseModel } from '@/model'
 import { 
   enterEdit, 
   isOld, 
@@ -35,7 +34,10 @@ Promise.all([
   initialGuides(),
   initialMeasures()
 ])
-.then(() => loaded.value = true)
+.then(() => {
+  loaded.value = true
+  loadModel(fuseModel)
+})
 
 router.beforeEach(async (to, from, next) => {
   if (to.params.save && isOld.value) {

+ 4 - 10
src/layout/edit/scene-edit.vue

@@ -1,9 +1,8 @@
 <template>
   <Header></Header>
   <LeftPano>
-    <SceneList v-model:current="currentModelType" />
+    <SceneList :current="currentModel" @update:current="loadModel" />
   </LeftPano>
-  <Model :type="currentModelType" />
 
   <router-view v-slot="{ Component }">
     <keep-alive>
@@ -14,20 +13,15 @@
 </template>
 
 <script setup lang="ts">
-import { ref, watchEffect } from 'vue'
 import Header from './header/index.vue'
 import SceneList from '../scene-list/index.vue'
-import { Model, FUSE } from '../model/index.vue'
 import { LeftPano } from '@/layout'
 import { custom } from '@/env'
+import { onMounted } from 'vue'
+import { currentModel, loadModel, fuseModel } from '@/model'
 
-import type { ModelType } from '../model/index.vue'
-
-const currentModelType = ref<ModelType>(FUSE)
-
-watchEffect(() => console.log(currentModelType.value))
+onMounted(() => loadModel(fuseModel))
 custom.showLeftPano = true
-
 </script>
 
 <style>

+ 1 - 3
src/layout/main.vue

@@ -18,11 +18,9 @@
 
 <script lang="ts" setup>
 import { custom } from '@/env'
-import { computed, watchEffect } from 'vue'
+import { computed } from 'vue'
 import { isEdit, appEl } from '@/store'
 
-watchEffect(() => console.log(appEl.value))
-
 const layoutClassNames = computed(() => {
   return {
     [`sys-view-${custom.viewMode}`]: true,

+ 0 - 83
src/layout/model/index.vue

@@ -1,83 +0,0 @@
-<template>
-  <iframe class="external" :src="url" v-if="url"></iframe>
-  <div class="laser-layer" v-show="!url">
-    <div class="scene-canvas" ref="fuseRef"></div>
-  </div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref, watchEffect, computed } from 'vue'
-import { initialSDK, initialed } from '@/sdk'
-import { getScene, SceneType } from '@/store'
-import { showModelsMapStack } from '@/env'
-
-import type { PropType } from 'vue'
-import type { Scene } from '@/store'
-
-export const FUSE = Symbol('fuse')
-export type ModelType = symbol | Scene['id']
-
-export const Model = defineComponent({
-  name: 'model',
-  props: {
-    type: {
-      type: [Number, Symbol] as PropType<ModelType>,
-      required: true
-    }
-  },
-  setup(props) {
-    const fuseRef = ref<HTMLDivElement>()
-    const stopSDKEffect = watchEffect(async () => {
-      if (!initialed && props.type === FUSE && fuseRef.value) {
-        await initialSDK({ layout: fuseRef.value })
-        stopSDKEffect()
-      }
-    })
-    const scene = computed(() => props.type !== FUSE && getScene(props.type as number))
-    const url = computed(() => {
-      if (!scene.value) return;
-      const type = scene.value.type
-      const kk = [SceneType.SWKK || SceneType.SWKJ]
-      const pathname = kk.includes(type) ? 'swkk/spg.html' : 'swss/uat/index.html'
-
-      return `/${pathname}?m=${scene.value.num}`
-    })
-    watchEffect((onCleanup) => {
-      if (url.value) {
-        onCleanup(showModelsMapStack.push(ref(new Map())))
-      }
-    })
-
-    return {
-      FUSE,
-      scene,
-      fuseRef,
-      url
-    }
-  }
-})
-
-export default Model
-</script>
-
-<style scoped lang="scss">
-.external,
-.laser-layer {
-  position: absolute;
-  z-index: 1;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-
-  .scene-canvas {
-    width: 100%;
-    height: 100%;
-    background-color: #ccc;
-  }
-}
-
-.external {
-  border: none;
-}
-</style>

+ 12 - 10
src/layout/scene-list/index.vue

@@ -5,23 +5,23 @@
     </template>
     <template #atom="{ item }">
       <div 
-        v-if="item.raw === FUSE" 
+        v-if="item.raw === fuseModel" 
         @click="$emit('update:current', current === item.raw ? null : item.raw)"
       >
         <ModelList
           class="model-list"
-          title="融合场景"
-          :show-content="current === FUSE"
+          :title="getModelTypeDesc(fuseModel as any)"
+          :show-content="current === fuseModel"
         >
           <template #action>
             <ui-icon 
-              :type="`pull-${current === FUSE ? 'up' : 'down'}`" 
+              :type="`pull-${current === fuseModel ? 'up' : 'down'}`" 
               ctrl 
             />
           </template>
         </ModelList>
       </div>
-      <div class="scene" @click="$emit('update:current', item.raw.id)" v-else>
+      <div class="scene" @click="$emit('update:current', {type: item.raw.type, num: item.raw.num})" v-else>
         <p>{{ item.raw.name }}</p>
         <p>{{ SceneTypeDesc[item.raw.type as SceneType] }}</p>
       </div>
@@ -30,13 +30,13 @@
 </template>
 
 <script lang="ts" setup>
-import { computed, ref } from 'vue'
+import { computed } from 'vue'
 import { scenes, SceneType, SceneTypeDesc } from '@/store'
-import { FUSE } from '../model/index.vue'
 import List from '@/components/list/index.vue'
 import ModelList from '../model-list/index.vue'
+import { fuseModel, getModelTypeDesc } from '@/model'
 
-import type { ModelType } from '../model/index.vue'
+import type { ModelType } from '@/model'
 
 defineEmits<{ (e: 'update:current', data: ModelType): void }>()
 const props = defineProps<{ current: ModelType }>()
@@ -44,9 +44,11 @@ const props = defineProps<{ current: ModelType }>()
 const list = computed(() => {
   const sceneList = scenes.value.map(scene => ({
     raw: scene,
-    select: props.current === scene.id
+    select: props.current !== fuseModel 
+      && props.current.num === scene.num 
+      && props.current.type === scene.type
   }))
-  return [{ raw: FUSE }, ...sceneList]
+  return [{ raw: fuseModel }, ...sceneList]
 })
 
 </script>

+ 100 - 0
src/model/app.vue

@@ -0,0 +1,100 @@
+<template>
+  <iframe class="external" :src="url" ref="iframeRef" v-if="url"></iframe>
+  <div class="laser-layer" v-show="!url">
+    <div class="scene-canvas" ref="fuseRef"></div>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref, watchEffect, computed, watch, onMounted, nextTick } from 'vue'
+import { SceneType } from '@/store'
+import { showModelsMapStack } from '@/env'
+import { fuseModel, modelProps } from './index'
+import { modelSDKFactory } from './platform'
+
+const typeChange = () => {
+  const oldType = modelProps.type
+  let stopWatch = null as unknown as () => void
+
+  const typePromise = new Promise((_, reject) => {
+    stopWatch = watchEffect(() => {
+      if (modelProps.type !== oldType) {
+        reject(new Error('当前模型未加载完已切换到下个'))
+        stopWatch!()
+      }
+    })
+  })
+  return { typePromise, typeCleanup: stopWatch }
+}
+
+export const Model = defineComponent({
+  name: 'model',
+  setup() {
+    const scene = computed(() => modelProps.type !== fuseModel && modelProps.type)
+    const url = computed(() => {
+      if (!scene.value) return;
+      const type = scene.value.type
+      const kk = [SceneType.SWKK || SceneType.SWKJ]
+      const pathname = kk.includes(type) ? 'swkk/spg.html' : 'swss/index.html'
+
+      return `/${pathname}?m=${scene.value.num}`
+    })
+    const fuseRef = ref<HTMLDivElement>()
+    const iframeRef = ref<HTMLIFrameElement>()
+
+    watch(
+      () => modelProps.type, 
+      async (type, oldType, onCleanup) => {
+        const callback = modelProps.callback
+
+        if (oldType === fuseModel) {
+          onCleanup(showModelsMapStack.push(ref(new Map())))
+        }
+
+        await nextTick()
+        const { typePromise, typeCleanup } = typeChange()
+        const modelPromise = modelSDKFactory(type, type === fuseModel ? fuseRef.value! : iframeRef.value!)
+        let result: any = null, error = null
+        try {
+          result = await Promise.race([typePromise, modelPromise])
+        } catch (err: Error) {
+          error = err
+        }
+        typeCleanup()
+        callback && callback(result, error)
+      }, 
+      { immediate: true, flush: 'post' }
+    )
+
+    return {
+      iframeRef,
+      fuseRef,
+      url
+    }
+  }
+})
+
+export default Model
+</script>
+
+<style scoped lang="scss">
+.external,
+.laser-layer {
+  position: absolute;
+  z-index: 1;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+
+  .scene-canvas {
+    width: 100%;
+    height: 100%;
+    background-color: #ccc;
+  }
+}
+
+.external {
+  border: none;
+}
+</style>

+ 63 - 0
src/model/index.ts

@@ -0,0 +1,63 @@
+import App from './app.vue'
+import { appEl, SceneTypeDesc } from '@/store'
+import { mount, deepIsRevise } from '@/utils'
+import { reactive, ref } from 'vue'
+
+import type { Scene } from '@/store'
+import type { ModelExpose } from './platform'
+
+export type FuseModelType = typeof fuseModel
+export type SceneModelType = Pick<Scene, 'type' | 'num'>
+export type ModelType = FuseModelType | SceneModelType
+export type ModelProps = { type: ModelType, callback: ((expose?: ModelExpose, err?: Error) => void) | null }
+export type { ModelExpose }
+
+export const fuseModel = Symbol('fuse')
+export const currentModel = ref<ModelType>(fuseModel)
+export const modelProps: ModelProps = reactive({ type: currentModel, callback: null })
+export const getModelTypeDesc = (model: ModelType) => {
+  if (model === fuseModel) {
+    return '融合场景'
+  } else {
+    return SceneTypeDesc[model.type]
+  }
+}
+
+const _loadModel = (() => {
+  let oldModelType: ModelType
+  let oldResult: Promise<ModelExpose>
+
+  return (modelType: ModelType) => {
+    if (!deepIsRevise(oldModelType, modelType)) {
+      return oldResult
+    }
+    console.log('加载', modelType)
+
+    oldModelType = modelType
+    return oldResult = new Promise<any>((resolve, reject) => {
+      modelProps.callback = (data: any, err) => {
+        if (err) {
+          reject(err)
+        } else {
+          resolve(data)
+        }
+      }
+      currentModel.value = modelType
+    })
+  }
+})();
+
+
+let isInitial = false
+export const loadModel = (modelType: ModelType): Promise<ModelExpose> => {
+  const modelPromise = _loadModel(modelType)
+  if (!isInitial) {
+    if (!appEl.value) {
+      throw new Error('appEl 未初始化')
+    } else {
+      mount(appEl.value, App)
+      isInitial = true
+    }
+  }
+  return modelPromise
+}

+ 160 - 0
src/model/platform.ts

@@ -0,0 +1,160 @@
+import { watchEffect, nextTick } from 'vue'
+import { fuseModelsLoaded, SceneType } from '@/store'
+import { fuseModel } from './'
+import { initialSDK, initialed as fuseInitialed, sdk as fuseSDK } from '@/sdk'
+import { asyncTimeout } from '@/utils'
+
+import type { ModelType } from './'
+
+export async function modelSDKFactory (
+  type: ModelType, 
+  dom: HTMLDivElement | HTMLIFrameElement
+): Promise<ModelExpose> {
+  if (type === fuseModel) {
+    if (!fuseInitialed) {
+      await initialSDK({ layout: dom })
+    }
+    return exposeFactory(fuseModel)
+  } else {
+    const iframe = dom as HTMLIFrameElement
+    const win = await new Promise<Window | null>((resolve, reject) => {
+      const loadedHandler = () => {
+        resolve(iframe.contentWindow)
+        cleanup()
+      }
+      const errorHandler = (err: any) => {
+        reject(err)
+        cleanup()
+      }
+      const cleanup = () => {
+        iframe.removeEventListener('load', loadedHandler)
+        iframe.removeEventListener('error', errorHandler)
+      }
+      iframe.addEventListener('load', loadedHandler)
+      iframe.addEventListener('error', errorHandler)
+    })
+
+    if (!win) {
+      throw new Error('场景加载失败')
+    }
+    return await exposeFactory(type, win)
+  }
+}
+
+
+const findObjectAttr = <T, K extends keyof T>(data: T, key: K): Promise<T[K]> => {
+  return new Promise<T[K]>(resolve => {
+    const query = () => {
+      if (key in data) {
+        resolve(data[key])
+      } else {
+        setTimeout(query, 6)
+      }
+    }
+    query()
+  })
+}
+
+const fuseLoaded = new Promise<void>(resolve => {
+  const stop = watchEffect(() => {
+    if (fuseModelsLoaded.value) {
+      resolve()
+      nextTick(() => stop())
+    }
+  })
+})
+
+export interface ModelExpose {
+  getView: () => Promise<{ image: Blob, flyData: string }>
+  setView: (flyData: string) => void
+}
+
+export async function exposeFactory(type: ModelType, win?: any): Promise<ModelExpose> {
+  const sceneType = type === fuseModel ? fuseModel : type.type
+  const platforms: {[key in any]: {getSDK: () => Promise<void>, expose: ModelExpose}} = {
+    [fuseModel]: {
+      getSDK: () => fuseLoaded,
+      expose: {
+        async getView() {
+          const dataURL = await fuseSDK.screenshot(260, 160)
+          const res = await fetch(dataURL)
+          const image = await res.blob()
+          const pose = fuseSDK.getPose()
+          return {
+            image,
+            flyData: JSON.stringify(pose)
+          }
+        },
+        async setView(flyData: string) {
+          const pose = JSON.parse(flyData)
+          fuseSDK.comeTo({ dur: 300, ...pose })
+        }
+      }
+    },
+    [SceneType.SWKK]: {
+      getSDK: async () => {
+        const sdk = await findObjectAttr(win , '__sdk')
+        if (!sdk.Scene.loaded) {
+          await new Promise(reoslve => sdk.Scene.on('loaded', reoslve))
+        }
+        return sdk
+      },
+      expose: {
+        async getView() {
+          const pose = sdk.Camera.getPose()
+          const images = await sdk.Camera.screenshot(
+            [{ width: 260, height: 160, name: '2k' }], 
+            true
+          )
+          return {
+            image: images[0].data, 
+            flyData: JSON.stringify(pose)
+          }
+        },
+        async setView(flyData: string) {
+          const pose = JSON.parse(flyData)
+          console.log('===>?', pose)
+          sdk.Camera.setPose({ dur: 300, ...pose })
+        }
+      }
+    },
+    [SceneType.SWSS]: {
+      getSDK: async () => {
+        await findObjectAttr(win, 'laserLoaded')
+        return await findObjectAttr(win, '__sdk')
+      },
+      expose: {
+        async getView() {
+          const dataURL = await sdk.scene.screenshot(260, 160)
+          const res = await fetch(dataURL)
+          const image = await res.blob()
+          const pose = await sdk.scene.getPose()
+          const mode = sdk.customMap.mode
+
+          return {
+            image, 
+            flyData: JSON.stringify({ pose, mode })
+          }
+        },
+        async setView(flyData: string) {
+          const { pose, mode } = JSON.parse(flyData)
+          sdk.customMap.mode  = mode
+          sdk.scene.setPose(pose, 300)
+          console.error('setView')
+        }
+      }
+    }
+  }
+  platforms[SceneType.SWKJ] = platforms[SceneType.SWKK]
+
+  if (!(sceneType in platforms)) {
+    throw new Error('不支持该类型场景!')
+  }
+
+  const sdk: any = await Promise.race([
+    asyncTimeout(10000)
+      .then(() => Promise.reject(new Error('加载超时'))),
+    platforms[sceneType].getSDK()
+  ])
+  return platforms[sceneType].expose
+}

+ 47 - 9
src/store/view.ts

@@ -16,22 +16,55 @@ import {
   postDeleteView,
   uploadFile
 } from '@/api'
+import { fuseModel } from '@/model'
 
 import type { View as SView } from '@/api'
+import type { ModelType } from '@/model'
 
 export type View = LocalMode<SView, 'cover'>
 export type Views = View[]
 
 export const views = ref<Views>([])
 
-export const createView = (): View => ({
-  id: createTemploraryID(),
-  title: '视图',
-  cover: 'https://4dkk.4dage.com/scene_view_data/KK-t-F8e5M46wcQ/images/floor_0.png?t=1659422513133?v=0&rnd=0.9219648338739086&x-oss-process=image/resize,m_fill,w_80,h_60/quality,q_70&rnd=0.25420557086595965',
-  flyData: '',
-  fusionId: fuseModels.value[0].fusionId,
-  sort: Math.min(...views.value.map(item => item.sort)) - 1,
-})
+export const createView = (view: Partial<View> = {}): View => {
+  const base = {
+    id: createTemploraryID(),
+    title: '视图',
+    cover: 'https://4dkk.4dage.com/scene_view_data/KK-t-F8e5M46wcQ/images/floor_0.png?t=1659422513133?v=0&rnd=0.9219648338739086&x-oss-process=image/resize,m_fill,w_80,h_60/quality,q_70&rnd=0.25420557086595965',
+    flyData: '',
+    num: null,
+    numType: null,
+    fusionId: fuseModels.value[0].fusionId,
+    sort: Math.min(...views.value.map(item => item.sort)) - 1,
+    ...view,
+  }
+  if (typeof view.fusionId === 'number') {
+    return {
+      ...base,
+      ...view,
+      fusionId: view.fusionId,
+      num: null,
+      numType: null
+    }
+  } else if (view.num && typeof view.numType === 'number') {
+    return {
+      ...base,
+      num: view.num,
+      numType: view.numType,
+      fusionId: null,
+    }
+  } else {
+    return base as View
+  }
+}
+
+export const viewToModelType = (view: View): ModelType => {
+  if (typeof view.fusionId === 'number') {
+    return fuseModel
+  } else {
+    return { num: view.num!, type: view.numType! }
+  }
+}
 
 
 let bcViews: Views = []
@@ -68,5 +101,10 @@ export const saveViews = saveStoreItems(
 export const autoSaveViews = autoSetModeCallback(views, {
   backup: backupViews,
   recovery: recoverViews,
-  save: saveViews
+  save: async () => {
+    for (let i = 0; i < views.value.length; i++) {
+      views.value[i].sort = i
+    }
+    await saveViews()
+  }
 })

+ 1 - 0
src/utils/index.ts

@@ -60,6 +60,7 @@ export const jsonToForm = (data: { [key in string]: any }) => {
   return formData
 }
 
+
 export * from './store-help'
 export * from "./stack";
 export * from "./loading";

+ 28 - 3
src/views/view/index.vue

@@ -1,7 +1,7 @@
 <template>
   <RightFillPano>
     <div class="btns header-btns">
-      <ui-button class="start" @click="start">
+      <ui-button class="start" @click="getView">
         <ui-icon type="add" />
         视图提取
       </ui-button>
@@ -26,15 +26,40 @@
 <script lang="ts" setup>
 import { views, createView, autoSaveViews, initialViews } from '@/store'
 import { RightFillPano } from '@/layout'
+import { useViewStack } from '@/hook'
 import Draggable from 'vuedraggable'
 import Sign from './sign.vue'
-import { useViewStack } from '@/hook'
+import { loadModel, currentModel, fuseModel } from '@/model'
+import { loadPack } from '@/utils'
+import { Message } from 'bill/index'
 
 import type { View } from '@/store'
 
 initialViews()
 
-const start = () => views.value.push(createView())
+const getView = async () => {
+  try {
+    const { image, flyData } = await loadPack(async () => {
+      const modelSDK = await loadModel(currentModel.value)
+      return await modelSDK.getView()
+    })
+
+    const type = currentModel.value !== fuseModel 
+      ? { numType: currentModel.value.type, num: currentModel.value.num }
+      : {}
+
+    views.value.push(createView({
+      flyData,
+      cover: {
+        blob: image,
+        url: URL.createObjectURL(image)
+      },
+      ...type
+    }))
+  } catch (e: Error) {
+    Message.error(e.message)
+  }
+}
 const deleteView = (record: View) => {
   const index = views.value.indexOf(record)
   if (~index) {

+ 29 - 44
src/views/view/sign.vue

@@ -1,7 +1,7 @@
 <template>
   <ui-group-option class="sign">
     <div class="content">
-      <span class="cover">
+      <span class="cover" @click="fly">
         <img :src="getResource(getFileUrl(view.cover))" alt="">
       </span>
       <ui-input 
@@ -12,9 +12,9 @@
         ref="inputRef" 
         height="28px" 
       />
-      <div class="title" v-show="!isEditTitle">
+      <div class="title" v-show="!isEditTitle" @click="fly">
         <p>{{ view.title }}</p>
-        <span>{{ view.title }}</span>
+        <span>{{ getModelTypeDesc(modelType as ModelType) }}</span>
       </div>
     </div>
     <div class="action">
@@ -28,54 +28,39 @@
   </ui-group-option>
 </template>
 
-<script lang="ts">
-import { defineComponent, ref, computed } from 'vue'
+<script lang="ts" setup>
+import { ref, computed } from 'vue'
 import { useFocus } from 'bill/hook/useFocus'
-import { Preview } from '@/components/static-preview/index.vue'
 import { getResource } from '@/env'
 import { getFileUrl } from '@/utils'
+import { loadModel, getModelTypeDesc, ModelType } from '@/model'
+import { viewToModelType } from '@/store'
 
-import type { PropType } from 'vue'
 import type { View } from '@/store'
 
-export default defineComponent({
-  props: {
-    view: {
-      type: Object as PropType<View>,
-      required: true
-    }
-  },
-  emits: {
-    'updateCover': (cover: string) => true,
-    'updateTitle': (title: string) => true,
-    'delete': () => true
-  },
-  setup(props, { emit }) {
-    const menus = [
-      { label: '编辑', value: 'rename' },
-      { label: '删除', value: 'delete' },
-    ]
-    
-    const inputRef = ref()
-    const isEditTitle = useFocus(computed(() => inputRef.value?.vmRef.root))
-    const actions = {
-      delete: () => emit('delete'),
-      rename: () => isEditTitle.value = true
-    }
+const props = defineProps<{ view: View }>()
+const emit = defineEmits<{
+    (e: 'updateCover', cover: string): void,
+    (e: 'updateTitle', title: string): void,
+    (e: 'delete'): void,
+}>()
 
-    return {
-      menus,
-      actions,
-      isEditTitle,
-      getFileUrl,
-      inputRef,
-      getResource
-    }
-  },
-  components: {
-    Preview
-  }
-})
+const menus = [
+  { label: '编辑', value: 'rename' },
+  { label: '删除', value: 'delete' },
+]
+
+const inputRef = ref()
+const isEditTitle = useFocus(computed(() => inputRef.value?.vmRef.root))
+const actions = {
+  delete: () => emit('delete'),
+  rename: () => isEditTitle.value = true
+}
+const modelType = viewToModelType(props.view)
+const fly = async () => {
+  const sdk = await loadModel(modelType)
+  sdk.setView(props.view.flyData)
+}
 </script>
 
 

+ 2 - 0
src/views/view/style.scss

@@ -54,6 +54,7 @@
     color: #fff;
     font-size: 16px;
     margin-right: 10px;
+    cursor: pointer;
 
     img {
       display: block;
@@ -63,6 +64,7 @@
   }
 
   .title {
+    cursor: pointer;
     p {
       font-size: 14px;
     }

+ 3 - 1
tsconfig.json

@@ -17,8 +17,10 @@
     "paths": {
       "bill/*": ["src/components/bill-ui/*"],
       "@/*": ["src/*"]
-    }
+    },
+    "outDir": "./dist"
   },
   "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
+  "exclude": ["src/components/bill-ui/*"],
   "references": [{ "path": "./tsconfig.node.json" }]
 }

+ 6 - 5
vite.config.ts

@@ -31,6 +31,11 @@ export default defineConfig({
         changeOrigin: true,
         rewrite: path => path.replace(/^\/local/, '')
       },
+      '/api/laser': {
+        target: 'https://uat-laser.4dkankan.com/',
+        changeOrigin: true,
+        rewrite: path => path.replace(/^\/api/, '')
+      },
       '/api': {
         target: 'http://192.168.0.47:8808',
         changeOrigin: true,
@@ -46,13 +51,9 @@ export default defineConfig({
         changeOrigin: true,
       },
       '/swss': {
-        target: 'https://uat-laser.4dkankan.com/',
+        target: 'http://localhost:8080/',
         changeOrigin: true,
         rewrite: path => path.replace(/^\/swss/, '')
-      },
-      '/laser': {
-        target: 'https://uat-laser.4dkankan.com/',
-        changeOrigin: true,
       }
     }
   }