ソースを参照

对接比例3d

bill 3 年 前
コミット
53bdbddf7f

+ 1 - 0
src/components/tagging/list.vue

@@ -33,6 +33,7 @@ const isShowSign = (modelId: string) => {
 
 const positions = computed(() => {
   const positions = getTaggingPositions(props.tagging)
+  console.error(positions)
   return positions
 })
 

+ 2 - 2
src/components/tagging/sign.vue

@@ -10,7 +10,7 @@
     <ui-tip :tip="tagging.title" foreShow tipV="top" class="tag-tip">
       <img 
         class="tag-img"
-        :src="getResource(taggingStyle.icon)" 
+        :src="getResource(getFileUrl(taggingStyle.icon))" 
         @click="iconClickHandler" 
         v-if="taggingStyle" 
       />
@@ -45,7 +45,7 @@
       <Preview 
         @close="pullIndex = -1"
         :type="MediaType.img" 
-        :url="getFileUrl(tagging.images[pullIndex])" 
+        :url="getResource(getFileUrl(tagging.images[pullIndex]))"
         v-if="!!~pullIndex" 
       />
     </div>

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

@@ -9,7 +9,8 @@
         @click="$emit('update:current', current === item.raw ? null : item.raw)"
       >
         <ModelList
-          class="model-list"
+          class="scene-model-list"
+          :class="{active: current === fuseModel}"
           :title="getModelTypeDesc(fuseModel as any)"
           :show-content="current === fuseModel"
         >
@@ -62,18 +63,25 @@ const list = computed(() => {
   padding: 0 20px;
 }
 
-.model-list.list {
+.scene-model-list.list {
   margin-bottom: -20px;
+  margin-top: -20px;
+
   .header {
-    padding: 10px 20px 20px;
+    padding: 30px 20px 20px;
     h3 {
       font-size: 20px;
       font-weight: bold;
       color: #FFFFFF;
     }
   }
+
+  &.active .header {
+    background-color: rgba(0, 200, 175, 0.16);
+  }
+
   .content li:last-child .atom-content {
     border: none;
   }
 }
-</style>
+</style>

+ 20 - 6
src/sdk/association.ts

@@ -1,7 +1,6 @@
 import { sdk } from './sdk'
-import { fuseModels, taggings, isEdit, sysBus, getFuseModelShowVariable, SceneType } from '@/store'
 import { toRaw, ref, watch, nextTick } from 'vue'
-import { viewModeStack, custom, getResource } from '@/env'
+import { viewModeStack, showLeftPanoStack, custom, getResource } from '@/env'
 import { 
   mount, 
   diffArrayChange, 
@@ -10,8 +9,18 @@ import {
   showLoad,
   hideLoad,
   deepIsRevise,
-  round
+  round,
+  togetherCallback
 } from '@/utils'
+import { 
+  fuseModels, 
+  taggings, 
+  isEdit, 
+  sysBus, 
+  getFuseModelShowVariable, 
+  SceneType,
+  backupFuseModels
+} from '@/store'
 
 import TaggingComponent from '@/components/tagging/list.vue'
 
@@ -92,12 +101,14 @@ const associationModels = (sdk: SDK) => {
       sceneModel.bus.on('loadDone', () => {
         item.loaded = true
         hideLoad()
+        backupFuseModels()
       })
       sceneModel.bus.on('loadError', () => {
         item.error = true
         item.show = false
         custom.showModelsMap.delete(item)
         hideLoad()
+        backupFuseModels()
       })
       sceneModel.bus.on('loadProgress', progress => item.progress = progress)
     }
@@ -115,8 +126,8 @@ const associationModels = (sdk: SDK) => {
           watch(() => item.bottom, () => isUnSet || getSceneModel(item)?.changeBottom(item.bottom), {immediate: true})
           watch(() => item.opacity, () => isUnSet || getSceneModel(item)?.changeOpacity(item.opacity), {immediate: true})
           watch(() => item.scale, () => isUnSet || getSceneModel(item)?.changeScale(item.scale), {immediate: true})
-          // watch(() => item.position, () => isUnSet || getSceneModel(item)?.changePosition(item.position), {immediate: true})
-          // watch(() => item.rotation, () => isUnSet || getSceneModel(item)?.changeRotation(item.rotation), {immediate: true})
+          watch(() => item.position, () => isUnSet || getSceneModel(item)?.changePosition(item.position), {immediate: true})
+          watch(() => item.rotation, () => isUnSet || getSceneModel(item)?.changeRotation(item.rotation), {immediate: true})
           watch(() => modelShow.value, () => isUnSet || getSceneModel(item)?.changeShow(modelShow.value), {immediate: true})
           stopLoadedWatch()
         }
@@ -143,7 +154,10 @@ const associationTaggings = (el: HTMLDivElement) => {
 
 
 const fullView = async (fn: () => void) => {
-  const popViewMode = viewModeStack.push(ref('full'))
+  const popViewMode = togetherCallback([
+    viewModeStack.push(ref('full')),
+    showLeftPanoStack.push(ref(false))
+  ])
   await document.documentElement.requestFullscreen()
   const driving = () => document.fullscreenElement || fn()
 

+ 7 - 0
src/sdk/sdk.ts

@@ -29,7 +29,14 @@ export type SceneModel = ToChangeAPI<SceneModelAttrs>
     leaveTransform: () => void
     enterAlignment: () => void
     leaveAlignment: () => void
+    enterScaleSet:() => ScaleSet
+    leaveScaleSet: () => void
   }
+
+export interface ScaleSet {
+  setLength: (length: number) => void,
+  startMeasure: () => void
+}
   
 
 export type ModelAttrRange = {

+ 29 - 0
src/views/guide/show.vue

@@ -0,0 +1,29 @@
+<template>
+  <ui-group title="导览列表" class="show-guides">
+    <GuideSign 
+      v-for="guide in guides" 
+      :key="guide.id" 
+      :guide="guide" 
+      :edit="false"
+    />
+  </ui-group>
+</template>
+
+<script setup lang="ts">
+import GuideSign from '@/views/guide/sign.vue'
+import { guides, initialGuides } from '@/store'
+
+initialGuides()
+</script>
+
+
+<style lang="scss">
+.show-guides.ui-group {
+   h3.group-title {
+    margin-bottom: 0;
+  }
+  .sign-guide:first-child {
+    border-top: none;
+  }
+}
+</style>

+ 6 - 2
src/views/guide/sign.vue

@@ -15,7 +15,7 @@
         <p>{{ guide.title }}</p>
       </div>
     </div>
-    <div class="actions">
+    <div class="actions" v-if="edit">
       <ui-more 
         :options="menus" 
         style="margin-left: 20px" 
@@ -32,7 +32,11 @@ import { getResource } from '@/env'
 import { computed } from 'vue';
 import { playSceneGuide } from '@/sdk'
 
-const props = defineProps<{ guide: Guide }>()
+const props = withDefaults(
+  defineProps<{ guide: Guide, edit?: boolean }>(),
+  { edit: true }
+)
+
 const emit = defineEmits<{ 
   (e: 'delete'): void 
   (e: 'play'): void 

+ 0 - 3
src/views/measure/index.vue

@@ -24,9 +24,7 @@
         v-for="measure in filterMeasures" 
         :key="measure.id" 
         :measure="measure" 
-        :selected="selectMeasure === measure"
         @delete="deleteMeasure(measure)"
-        @select="selectMeasure = measure"
       />
     </ui-group>
   </RightFillPano>
@@ -54,7 +52,6 @@ import type { ActionsItem } from '@/components/actions/index.vue'
 
 const keyword = ref('')
 const filterMeasures = computed(() => measures.value.filter(measure => measure.desc.includes(keyword.value)))
-const selectMeasure = ref<Measure | null>(null)
 const editMeasure = ref<Measure | null>(null)
 const enterCreateMeasure = (type: MeasureType) => {
   editMeasure.value = createMeasure({ type })

+ 32 - 0
src/views/measure/show.vue

@@ -0,0 +1,32 @@
+<template>
+  <ui-group title="测量列表" class="show-measures">
+    <template #icon>
+      <ui-icon 
+        ctrl
+        :type="custom.showMeasures ? 'eye-s' : 'eye-n'" 
+        @click="custom.showMeasures = !custom.showMeasures" 
+      />
+    </template>
+    <MeasureSign 
+      v-for="measure in measures" 
+      :key="measure.id" 
+      :measure="measure" 
+      :edit="false"
+    />
+  </ui-group>
+</template>
+
+<script setup lang="ts">
+import MeasureSign from '@/views/measure/sign.vue'
+import { measures, initialMeasures } from '@/store'
+import { custom } from '@/env'
+
+initialMeasures() 
+</script>
+
+
+<style lang="scss">
+.show-measures.ui-group > h3.group-title {
+  margin-bottom: 0;
+}
+</style>

+ 6 - 19
src/views/measure/sign.vue

@@ -1,9 +1,5 @@
 <template>
-  <ui-group-option 
-    class="sign-measure" 
-    :class="{active: selected}" 
-    @click="emit('select')"
-  >
+  <ui-group-option class="sign-measure">
     <div class="info">
       <ui-icon :type="MeasureTypeMeta[measure.type].icon" class="type" />
       <div>
@@ -12,7 +8,7 @@
       </div>
     </div>
     <div class="actions" @click.stop>
-      <ui-icon type="del" ctrl @click.stop="$emit('delete')" />
+      <ui-icon type="del" ctrl @click.stop="$emit('delete')" v-if="edit" />
       <ui-icon type="pin" ctrl @click.stop="$emit('fly')" />
     </div>
   </ui-group-option>
@@ -23,12 +19,13 @@ import { MeasureTypeMeta } from '@/store'
 
 import type { Measure } from '@/store'
 
-
-defineProps<{ measure: Measure, selected?: boolean }>()
+withDefaults(
+  defineProps<{ measure: Measure, edit?: boolean }>(),
+  { edit: true }
+)
 
 const emit = defineEmits<{ 
   (e: 'delete'): void 
-  (e: 'select'): void
   (e: 'fly'): void
 }>()
 
@@ -42,18 +39,8 @@ const emit = defineEmits<{
   padding: 20px 0;
   margin: 0;
   border-bottom: 1px solid var(--colors-border-color);
-  cursor: pointer;
   position: relative;
 
-  &.active::after {
-    content: '';
-    position: absolute;
-    pointer-events: none;
-    inset: 0 -20px;
-    background-color: rgba(0, 200, 175, 0.16);
-    z-index: -1;
-  }
-
   .info {
     flex: 1;
 

+ 44 - 8
src/views/proportion/index.vue

@@ -1,25 +1,61 @@
 <template>
-  <ui-editor-toolbar toolbar>
+  <ui-editor-toolbar toolbar v-if="sceneModel">
     <span>长度:</span>
-    <ui-input type="number" width="120px" class="leng-input" :ctrl="false">
+    <ui-input 
+      type="number" 
+      width="120px" 
+      class="leng-input" 
+      :ctrl="false" 
+      v-model="length"
+    >
       <template #icon>m</template>
     </ui-input>
-    <ui-button type="submit" width="160px">重新选点</ui-button>
+    <ui-button type="submit" width="160px" @click="scaleSet?.startMeasure()">重新选点</ui-button>
   </ui-editor-toolbar>
 </template>
 
 <script lang="ts" setup>
 import { Message } from 'bill/index'
 import { useViewStack } from '@/hook'
+import { router } from '@/router'
+import { ref, computed, watchEffect } from 'vue'
+import { getSceneModel } from '@/sdk'
+import { autoSaveFuseModels, getFuseModel, leave } from '@/store'
 
-useViewStack(() => {
-  const hide = Message.show({ msg: '请选择两点标记一段已知长度,并输入真实长度' })
-  return () => {
-    console.log(hide)
-    hide()
+import type { ScaleSet } from '@/sdk'
+
+const model = computed(() => {
+  const modelId = router.currentRoute.value.params.id as string
+  if (modelId) {
+    return getFuseModel(modelId)
   }
 })
 
+const sceneModel = computed(() => model.value && getSceneModel(model.value))
+
+let scaleSet: ScaleSet | null = null
+const length = ref<number>()
+
+watchEffect(() => {
+  length.value && scaleSet?.setLength(length.value)
+})
+
+useViewStack(() => {
+  if (sceneModel.value) {
+    const model = sceneModel.value
+    scaleSet = model.enterScaleSet()
+    scaleSet.startMeasure()
+    
+    return () => {
+      model.leaveAlignment()
+      scaleSet = null
+    }
+  } else {
+    leave()
+  }
+})
+useViewStack(Message.show({ msg: '请选择两点标记一段已知长度,并输入真实长度' }))
+useViewStack(autoSaveFuseModels)
 </script>
 
 <style lang="scss" scoped>

+ 6 - 1
src/views/record/sign.vue

@@ -24,7 +24,7 @@
         <span v-if="record.status === RecordStatus.RUN">后台正在处理</span>
       </div>
     </div>
-    <div class="action">
+    <div class="action" v-if="edit">
       <ui-icon type="order" ctrl />
       <ui-more 
         :options="menus" 
@@ -68,6 +68,11 @@ export default defineComponent({
     record: {
       type: Object as PropType<RecordProcess>,
       required: true
+    },
+    edit: {
+      type: Boolean,
+      required: false,
+      default: true
     }
   },
   emits: {

+ 66 - 40
src/views/summary/index.vue

@@ -4,62 +4,88 @@
   </LeftPano>
 
   <RightFillPano>
-    <ui-group>
-      <TaggingSign 
-        v-for="tagging in taggings" 
-        :key="tagging.id" 
-        :tagging="tagging" 
-      />
-    </ui-group>
-    <ui-group>
-      <MeasureSign 
-        v-for="measure in measures" 
-        :key="measure.id" 
-        :measure="measure" 
-      />
-    </ui-group>
-    <ui-group>
-      <GuideSign 
-        v-for="guide in guides" 
-        :key="guide.id" 
-        :guide="guide" 
-      />
-    </ui-group>
+    <div class="tabs">
+      <span 
+        v-for="tab in tabs"
+        :key="tab.key"
+        :class="{ active: tab.key === current }"
+        @click="current = tab.key"
+      >
+        {{tab.text}}
+      </span>
+    </div>
+    <Taggings v-show="current === TabKey.tagging" />
+    <Guides  v-show="current === TabKey.guide"/>
+    <Measures  v-show="current === TabKey.measure"/>
   </RightFillPano>
 </template>
 
 <script setup lang="ts">
-import { computed } from 'vue'
+import { computed, ref } from 'vue'
 import { useViewStack } from '@/hook'
 import { togetherCallback } from '@/utils'
 import { showRightCtrlPanoStack, showRightPanoStack } from '@/env'
 import { currentModel, fuseModel, loadModel } from '@/model'
 import { LeftPano, RightFillPano } from '@/layout'
 import SceneList from '@/layout/scene-list/index.vue'
-import TaggingSign from '@/views/tagging/sign.vue'
-import MeasureSign from '@/views/measure/sign.vue'
-import GuideSign from '@/views/guide/sign.vue'
-import { 
-  taggings, 
-  guides, 
-  measures, 
-  initialTaggings, 
-  initialGuides, 
-  initialMeasures,
-  initialTaggingStyles,
-} from '@/store'
+import Taggings from '@/views/tagging/show.vue'
+import Measures from '@/views/measure/show.vue'
+import Guides from '@/views/guide/show.vue'
 
-initialTaggingStyles()
-initialTaggings() 
-initialGuides()
-initialMeasures() 
+enum TabKey { tagging, measure, guide }
+const tabs = [
+  { key: TabKey.tagging, text: '标注' },
+  { key: TabKey.measure, text: '测量' },
+  { key: TabKey.guide, text: '路径' },
+]
+const current = ref(tabs[0].key)
 
 const showRightPano = computed(() => currentModel.value === fuseModel)
-
 useViewStack(
   () => togetherCallback([
     showRightCtrlPanoStack.push(showRightPano), 
     showRightPanoStack.push(showRightPano)
   ])
 )
-</script>
+</script>
+
+<style lang="scss" scoped>
+.tabs {
+  height: 60px;
+  border-bottom: 1px solid rgba(255,255,255,0.16);
+  display: flex;
+  margin: -20px;
+  margin-bottom: 20px;
+
+  > span {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: relative;
+    transition: color .3s ease;
+    cursor: pointer;
+    font-size: 16px;
+
+    &::after {
+      content: '';
+      transition: height .3s ease;
+      position: absolute;
+      background-color: #00C8AF;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      height: 0;
+    }
+
+    &:hover,
+    &.active {
+      color: #00C8AF;
+    }
+
+    &.active::after {
+      height: 3px;
+    }
+  }
+}
+</style>

+ 43 - 0
src/views/tagging/show.vue

@@ -0,0 +1,43 @@
+<template>
+  <ui-group title="标注列表" class="show-taggings">
+    <template #icon>
+      <ui-icon 
+        ctrl
+        :type="custom.showTaggings ? 'eye-s' : 'eye-n'" 
+        @click="custom.showTaggings = !custom.showTaggings" 
+      />
+    </template>
+    <TaggingSign 
+      v-for="tagging in taggings" 
+      :key="tagging.id" 
+      :tagging="tagging" 
+      :selected="selectTagging === tagging"
+      :edit="false"
+      @select="selected => selectTagging = selected ? tagging : null"
+      class="show-tagging"
+    />
+  </ui-group>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import { custom } from '@/env'
+import TaggingSign from './sign.vue'
+import { taggings, initialTaggings, initialTaggingStyles } from '@/store'
+
+import type { Tagging } from '@/store'
+
+initialTaggingStyles()
+initialTaggings() 
+
+const selectTagging = ref<Tagging | null>(null)
+</script>
+
+<style lang="scss">
+.show-taggings.ui-group > h3.group-title {
+  margin-bottom: 0;
+}
+.show-tagging.sign-tagging.active::after {
+  display: none;
+}
+</style>

+ 15 - 9
src/views/tagging/sign.vue

@@ -1,8 +1,8 @@
 <template>
   <ui-group-option 
     class="sign-tagging" 
-    :class="{active: selected}" 
-    @click="!disabledFly && emit('select', true)"
+    :class="{active: selected, edit}" 
+    @click="edit && !disabledFly && emit('select', true)"
   >
     <div class="info">
       <img :src="getResource(getFileUrl(tagging.images.length ? tagging.images[0] : style.icon))" v-if="style">
@@ -12,12 +12,15 @@
       </div>
     </div>
     <div class="actions" @click.stop>
-      <ui-icon type="pin1" ctrl @click.stop="$emit('fixed')" />
-      <ui-more 
-        :options="menus" 
-        style="margin-left: 20px" 
-        @click="(action: keyof typeof actions) => actions[action]()" 
-      />
+      <ui-icon type="pin" ctrl @click.stop="$emit('select', true)" v-if="!edit"/>
+      <template v-else>
+        <ui-icon type="pin1" ctrl @click.stop="$emit('fixed')" />
+        <ui-more 
+          :options="menus" 
+          style="margin-left: 20px" 
+          @click="(action: keyof typeof actions) => actions[action]()" 
+        />
+      </template>
     </div>
   </ui-group-option>
 </template>
@@ -36,7 +39,10 @@ import {
 
 import type { Tagging } from '@/store'
 
-const props = defineProps<{ tagging: Tagging, selected?: boolean }>()
+const props = withDefaults(
+  defineProps<{ tagging: Tagging, selected?: boolean, edit?: boolean }>(),
+  { edit: true }
+)
 const style = computed(() => getTaggingStyle(props.tagging.styleId))
 const positions = computed(() => getTaggingPositions(props.tagging))
 const disabledFly = computed(() => 

+ 9 - 7
src/views/tagging/style.scss

@@ -5,15 +5,17 @@
   padding: 20px 0;
   margin: 0;
   border-bottom: 1px solid var(--colors-border-color);
-  cursor: pointer;
   position: relative;
 
-  &.active::after {
-    content: '';
-    position: absolute;
-    pointer-events: none;
-    inset: 0 -20px;
-    background-color: rgba(0, 200, 175, 0.16);
+  &.edit{
+    cursor: pointer;
+    .active::after {
+      content: '';
+      position: absolute;
+      pointer-events: none;
+      inset: 0 -20px;
+      background-color: rgba(0, 200, 175, 0.16);
+    }
   }
 
   .info {

+ 5 - 2
src/views/view/sign.vue

@@ -17,7 +17,7 @@
         <span>{{ getModelTypeDesc(modelType as ModelType) }}</span>
       </div>
     </div>
-    <div class="action">
+    <div class="action" v-if="edit">
       <ui-icon type="order" ctrl />
       <ui-more 
         :options="menus" 
@@ -38,7 +38,10 @@ import { viewToModelType } from '@/store'
 
 import type { View } from '@/store'
 
-const props = defineProps<{ view: View }>()
+const props = withDefaults(
+  defineProps<{ view: View, edit?: boolean }>(),
+  { edit: true }
+)
 const emit = defineEmits<{
     (e: 'updateCover', cover: string): void,
     (e: 'updateTitle', title: string): void,