Procházet zdrojové kódy

Merge branch 'local' of http://192.168.0.115:3000/bill/fuse-code into local

xzw před 3 roky
rodič
revize
27029af3a1

+ 72 - 3
src/components/bill-ui/components/icon/iconfont/demo_index.html

@@ -55,6 +55,24 @@
           <ul class="icon_lists dib-box">
           
             <li class="dib">
+              <span class="icon iconfont">&#xe64c;</span>
+                <div class="name">search</div>
+                <div class="code-name">&amp;#xe64c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6ae;</span>
+                <div class="name">left</div>
+                <div class="code-name">&amp;#xe6ae;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6af;</span>
+                <div class="name">right</div>
+                <div class="code-name">&amp;#xe6af;</div>
+              </li>
+          
+            <li class="dib">
               <span class="icon iconfont">&#xe624;</span>
                 <div class="name">state_e</div>
                 <div class="code-name">&amp;#xe624;</div>
@@ -246,9 +264,9 @@
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.woff2?t=1660619600055') format('woff2'),
-       url('iconfont.woff?t=1660619600055') format('woff'),
-       url('iconfont.ttf?t=1660619600055') format('truetype');
+  src: url('iconfont.woff2?t=1660727466034') format('woff2'),
+       url('iconfont.woff?t=1660727466034') format('woff'),
+       url('iconfont.ttf?t=1660727466034') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -275,6 +293,33 @@
         <ul class="icon_lists dib-box">
           
           <li class="dib">
+            <span class="icon iconfont icon-search"></span>
+            <div class="name">
+              search
+            </div>
+            <div class="code-name">.icon-search
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-left1"></span>
+            <div class="name">
+              left
+            </div>
+            <div class="code-name">.icon-left1
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-right"></span>
+            <div class="name">
+              right
+            </div>
+            <div class="code-name">.icon-right
+            </div>
+          </li>
+          
+          <li class="dib">
             <span class="icon iconfont icon-state_e"></span>
             <div class="name">
               state_e
@@ -564,6 +609,30 @@
           
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-search"></use>
+                </svg>
+                <div class="name">search</div>
+                <div class="code-name">#icon-search</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-left1"></use>
+                </svg>
+                <div class="name">left</div>
+                <div class="code-name">#icon-left1</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-right"></use>
+                </svg>
+                <div class="name">right</div>
+                <div class="code-name">#icon-right</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#icon-state_e"></use>
                 </svg>
                 <div class="name">state_e</div>

+ 15 - 3
src/components/bill-ui/components/icon/iconfont/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 3549513 */
-  src: url('iconfont.woff2?t=1660619600055') format('woff2'),
-       url('iconfont.woff?t=1660619600055') format('woff'),
-       url('iconfont.ttf?t=1660619600055') format('truetype');
+  src: url('iconfont.woff2?t=1660727466034') format('woff2'),
+       url('iconfont.woff?t=1660727466034') format('woff'),
+       url('iconfont.ttf?t=1660727466034') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,18 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-search:before {
+  content: "\e64c";
+}
+
+.icon-left1:before {
+  content: "\e6ae";
+}
+
+.icon-right:before {
+  content: "\e6af";
+}
+
 .icon-state_e:before {
   content: "\e624";
 }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
src/components/bill-ui/components/icon/iconfont/iconfont.js


+ 21 - 0
src/components/bill-ui/components/icon/iconfont/iconfont.json

@@ -6,6 +6,27 @@
   "description": "",
   "glyphs": [
     {
+      "icon_id": "25631464",
+      "name": "search",
+      "font_class": "search",
+      "unicode": "e64c",
+      "unicode_decimal": 58956
+    },
+    {
+      "icon_id": "27765016",
+      "name": "left",
+      "font_class": "left1",
+      "unicode": "e6ae",
+      "unicode_decimal": 59054
+    },
+    {
+      "icon_id": "27765017",
+      "name": "right",
+      "font_class": "right",
+      "unicode": "e6af",
+      "unicode_decimal": 59055
+    },
+    {
       "icon_id": "22132762",
       "name": "state_e",
       "font_class": "state_e",

binární
src/components/bill-ui/components/icon/iconfont/iconfont.ttf


binární
src/components/bill-ui/components/icon/iconfont/iconfont.woff


binární
src/components/bill-ui/components/icon/iconfont/iconfont.woff2


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

@@ -14,7 +14,11 @@
                 <span class="range-slide" @click.stop @touchstart="slideDownHandler" @mousedown="slideDownHandler"></span>
             </div>
         </div>
-        <UInumber v-if="props.input" :modelValue="modelValue" @update:modelValue="inputUpdateHandler" :min="min" :max="max" :step="step" class="range-text" />
+        <UInumber v-if="props.input" :ctrl="ctrl" :modelValue="modelValue" @update:modelValue="inputUpdateHandler" :min="min" :max="max" :step="step" class="range-text">
+            <template v-for="(slot, name) in $slots" v-slot:[name]="raw">
+                <slot :name="name" v-bind="raw" />
+            </template>
+        </UInumber>
     </div>
 </template>
 
@@ -25,6 +29,7 @@ import UInumber from './number.vue'
 import { os } from '../../utils/index'
 
 const props = defineProps(rangePropsDesc)
+
 const emit = defineEmits(['update:modelValue'])
 const getValue = value => {
     const calcStep = Math.ceil(1 / props.step)

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

@@ -3,6 +3,7 @@
     <template v-for="(pos, index) in positions" :key="pos.id">
       <Sign 
         v-if="isShowSign(pos.modelId)"
+        @delete="deletePosition(pos)"
         :tagging="tagging"
         :scene-pos="pos"
       />
@@ -13,7 +14,7 @@
 <script lang="ts" setup>
 import { computed } from 'vue'
 import Sign from './sign.vue'
-import { Tagging, getModelShowVariable, getModel, getTaggingPositions } from '@/store';
+import { Tagging, getModelShowVariable, getModel, getTaggingPositions, TaggingPosition, taggingPositions } from '@/store';
 import { custom } from '@/env'
 
 const props = defineProps<{ tagging: Tagging }>()
@@ -28,4 +29,9 @@ const positions = computed(() => {
   return positions
 })
 
+const deletePosition = (pos: TaggingPosition) => {
+  const index = taggingPositions.value.indexOf(pos)
+  taggingPositions.value.splice(index, 1)
+}
+
 </script>

+ 37 - 6
src/components/tagging/sign.vue

@@ -6,11 +6,14 @@
     @mouseenter="isHover = true"
     @mouseleave="isHover = false"
   >
-    <img 
-      :src="getResource(taggingStyle.icon)" 
-      @click="iconClickHandler" 
-      v-if="taggingStyle" 
-    />
+    <ui-tip :tip="tagging.title" foreShow tipV="top" class="tag-tip">
+      <img 
+        class="tag-img"
+        :src="getResource(taggingStyle.icon)" 
+        @click="iconClickHandler" 
+        v-if="taggingStyle" 
+      />
+    </ui-tip>
     <div @click.stop>
       <UIBubble
         class="hot-bubble pc" 
@@ -30,6 +33,12 @@
           :in-full="true" 
           @pull="index => (pullIndex = index)" 
         />
+        <div class="edit-hot" v-if="router.currentRoute.value.name === RoutesName.tagging">
+          <span @click="$emit('delete')" class="fun-ctrl">
+            <ui-icon type="del" />
+            删除
+          </span>
+        </div>
       </UIBubble>
 
       <Preview 
@@ -44,6 +53,7 @@
 
 <script lang="ts" setup>
 import { computed, ref, watchEffect, watch } from 'vue'
+import { router, RoutesName } from '@/router'
 import UIBubble from 'bill/components/bubble/index.vue'
 import Images from '@/views/tagging/images.vue'
 import Preview, { MediaType } from '../static-preview/index.vue'
@@ -56,6 +66,7 @@ import type { Tagging, TaggingPosition } from '@/store';
 
 export type SignProps = { tagging: Tagging, scenePos: TaggingPosition, show?: boolean }
 
+defineEmits<{ (e: 'delete'): void }>()
 
 const props = defineProps<SignProps>()
 const posStyle = ref<null | { left: string, top: string}>(null)
@@ -103,7 +114,7 @@ const iconClickHandler = () => {
   transform: translate(-50%, -50%);
   cursor: pointer;
 
-  > img {
+  .tag-img {
     width: 32px;
     height: 32px;
   }
@@ -146,4 +157,24 @@ const iconClickHandler = () => {
   }
 }
 
+.edit-hot {
+  margin-top: 20px;
+  text-align: right;
+
+  span {
+    font-size: 14px;
+    color: rgba(255, 255, 255, 0.6);
+    cursor: pointer;
+  }
+}
+
+</style>
+
+<style>
+.tag-tip {
+  z-index: 8 !important;
+}
+.tag-tip p {
+  margin: 5px 0 !important;
+}
 </style>

+ 13 - 4
src/layout/model-list/index.vue

@@ -5,16 +5,16 @@
       key="id" 
       :data="modelList" 
     >
-      <template #action>
+      <template #action v-if="custom.modelsChangeStore">
         <ui-input
           type="file"
           width="20px"
           placeholder="上传模型"
-          othPlaceholder="支持RAR,ZIP压缩包格式"
-          accept=".rar, .zip"
+          othPlaceholder="支持ZIP压缩包格式"
+          accept=".zip"
           :disable="true"
           :multiple="false"
-          @update:modelValue="addModel"
+          @update:modelValue="addHandler"
         >
           <template v-slot:replace>
             <ui-icon type="add" ctrl/>
@@ -50,6 +50,15 @@ const modelList = computed(() =>
   }))
 )
 
+const addHandler = async (file: File) => {
+  await addModel(file)
+  modelList.value.forEach(model => {
+    if (!custom.showModelsMap.has(model.raw)) {
+      custom.showModelsMap.set(model.raw, model.raw.show)
+    }
+  })
+}
+
 const modelChangeSelect = (model: Model) => {
   if (getModelShowVariable(model).value) {
     if (custom.currentModel !== model) {

+ 5 - 5
src/layout/model-list/sign.vue

@@ -1,20 +1,20 @@
 <template>
-  <div class="model-header" :class="{disabled: model.error}" @click="$emit('click')">
+  <div class="model-header" @click="!model.error && $emit('click')">
     <p>{{ model.title }}</p>
     <div class="model-action" @click.stop>
-      <ui-input type="checkbox" v-model="show" />
+      <ui-input type="checkbox" v-model="show" :class="{disabled: model.error}"/>
       <ui-icon 
+        v-if="custom.modelsChangeStore && model.type !== ModelType.SWSS"
         type="del" 
         ctrl 
         @click="$emit('delete')" 
-        v-if="model.type !== ModelType.SWSS && custom.modelsChangeStore" 
       />
     </div>
   </div>
-  <div class="model-desc" @click="$emit('click')">
+  <div class="model-desc" @click="$emit('click')" v-if="custom.currentModel === model">
     <p><span>数据来源:</span>{{ ModelTypeDesc[model.type] }}</p>
     <p><span>数据大小:</span>{{ model.size }}</p>
-    <p><span>拍摄时间:</span>{{ model.time }}</p>
+    <p v-if="model.type === ModelType.SWSS"><span>拍摄时间:</span>{{ model.time }}</p>
   </div>
 </template>
 

+ 3 - 2
src/sdk/association.ts

@@ -52,7 +52,6 @@ const associationModels = (sdk: SDK) => {
         hideLoad()
       })
       sceneModel.bus.on('loadError', () => {
-        console.error(item, '加载失败')
         item.error = true
         item.show = false
         custom.showModelsMap.delete(item)
@@ -71,7 +70,9 @@ const associationModels = (sdk: SDK) => {
       (loaded) => {
         if (loaded) {
           const modelShow = getModelShowVariable(item)
-          watchEffect(() => getSceneModel(item)?.changeBottom(item.bottom))
+          watchEffect(() => {
+            getSceneModel(item)?.changeBottom(item.bottom)
+          })
           watchEffect(() => getSceneModel(item)?.changeOpacity(item.opacity))
           watchEffect(() => getSceneModel(item)?.changeScale(item.scale))
           watchEffect(() => getSceneModel(item)?.changeShow(modelShow.value))

+ 6 - 4
src/views/guide/edit-paths.vue

@@ -86,7 +86,7 @@
 import { loadPack, togetherCallback, getFileUrl, asyncTimeout } from '@/utils'
 import { sdk, playSceneGuide, pauseSceneGuide, isScenePlayIng } from '@/sdk'
 import { createGuidePath, isTemploraryID, useAutoSetMode, guides } from '@/store'
-import { Dialog } from 'bill/index'
+import { Dialog, Message } from 'bill/index'
 import { useViewStack } from '@/hook'
 import { nextTick, ref, toRaw, watchEffect } from 'vue'
 import { showRightPanoStack, showLeftCtrlPanoStack, showLeftPanoStack, showRightCtrlPanoStack, getResource } from '@/env'
@@ -118,10 +118,12 @@ useViewStack(() =>
 
 useAutoSetMode(paths, {
   save() {
-    props.data.paths = paths.value
-    if (paths.value.length) {
-      props.data.cover = paths.value[0].cover
+    if (!paths.value.length) {
+      Dialog.alert('无法保存空路径导览!')
+      throw '无法保存空路径导览!'
     }
+    props.data.paths = paths.value
+    props.data.cover = paths.value[0].cover
     if (isTemploraryID(props.data.id)) {
       guides.value.push(props.data)
     }

+ 23 - 8
src/views/merge/index.vue

@@ -8,19 +8,25 @@
         <!-- <template #icon>
           <a href="">设置比例</a>
         </template> -->
-        <ui-input type="range" v-model="custom.currentModel.scale" v-bind="scaleOption" width="100%" />
+        <ui-input type="range" v-model="custom.currentModel.scale" v-bind="scaleOption" width="100%">
+          <template #icon>%</template>
+        </ui-input>
       </ui-group-option>
       <ui-group-option label="离地高度">
-        <ui-input type="range" v-model="custom.currentModel.bottom" v-bind="bottomOption" width="100%" />
+        <ui-input type="range" v-model="custom.currentModel.bottom" v-bind="bottomOption" width="100%">
+          <template #icon>m</template>
+        </ui-input>
       </ui-group-option>
       <ui-group-option label="模型不透明度">
-        <ui-input type="range" v-model="custom.currentModel.opacity" v-bind="opacityOption" width="100%" />
+        <ui-input type="range" v-model="custom.currentModel.opacity" v-bind="opacityOption" width="100%">
+          <template #icon>%</template>
+        </ui-input>
       </ui-group-option>
       <!-- <ui-group-option>
         <ui-button>配准</ui-button>
       </ui-group-option> -->
       <ui-group-option>
-        <ui-button @click="Object.assign(custom.currentModel as any, defaultAttrs)">恢复默认</ui-button>
+        <ui-button @click="reset">恢复默认</ui-button>
       </ui-group-option>
     </ui-group>
   </RightPano>
@@ -34,7 +40,8 @@ import Actions from '@/components/actions/index.vue'
 import { getSceneModel } from '@/sdk'
 import { useViewStack } from '@/hook'
 import { showLeftCtrlPanoStack, showLeftPanoStack, custom, modelsChangeStoreStack } from '@/env'
-import { ref } from 'vue'
+import { ref, nextTick } from 'vue'
+import { Dialog } from 'bill/expose-common'
 
 import type { ActionsProps } from '@/components/actions/index.vue'
 
@@ -51,9 +58,9 @@ const defaultAttrs: ModelAttrs = {
   position: {x: 0, y: 0, z: 0},
   rotation: {x: 0, y: 0, z: 0}
 }
-const opacityOption = { min: 0.01, max: 1, step: 0.01, }
-const bottomOption = { min: 1, max: 100, step: 1, }
-const scaleOption = { min: 0.01, max: 1, step: 0.01, }
+const opacityOption = { min: 0, max: 100, step: 0.01, ctrl: false }
+const bottomOption = { min: -30, max: 70, step: 0.1, ctrl: false }
+const scaleOption = { min: 0, max: 200, step: 0.01, ctrl: false }
 const actionItems: ActionsProps['items'] = [
   {
     icon: 'move',
@@ -76,6 +83,14 @@ const actionItems: ActionsProps['items'] = [
   },
 ]
 
+const reset = async () => {
+  if (custom.currentModel && await Dialog.confirm('确定恢复默认?此操作无法撤销')) {
+    Object.assign(custom.currentModel, defaultAttrs)
+    await nextTick()
+    custom.currentModel && (custom.currentModel.bottom = 0)
+  }
+}
+
 useViewStack(() => togetherCallback([
   showLeftCtrlPanoStack.push(ref(false)),
   showLeftPanoStack.push(ref(true)),

+ 2 - 0
src/views/tagging/edit.vue

@@ -122,6 +122,8 @@ const tagging = ref<Tagging>({...props.data, images: [...props.data.images]})
 const submitHandler = () => {
   if (!tagging.value.title.trim()) {
     Message.error('标注标题必须填写!')
+  } else if (!tagging.value.images.length) {
+    Message.error('至少上传一张图片!')
   } else {
     emit('save', tagging.value)
   }

+ 5 - 3
src/views/tagging/index.vue

@@ -17,14 +17,14 @@
         />
       </template>
       <ui-group-option>
-        <ui-input type="text" width="100%" placeholder="搜索">
+        <ui-input type="text" width="100%" placeholder="搜索" v-model="keyword">
           <template #preIcon>
             <ui-icon type="search" />
           </template>
         </ui-input>
       </ui-group-option>
       <TagingSign 
-        v-for="tagging in taggings" 
+        v-for="tagging in filterTaggings" 
         :key="tagging.id" 
         :tagging="tagging" 
         :selected="selectTagging === tagging"
@@ -51,7 +51,7 @@ import { Message } from 'bill/index'
 import { RightFillPano } from '@/layout'
 import { togetherCallback } from '@/utils'
 import { useViewStack } from '@/hook'
-import { ref, watch } from 'vue';
+import { computed, ref, watch } from 'vue';
 import { sdk } from '@/sdk'
 import { 
   taggings, 
@@ -77,6 +77,8 @@ import {
   showRightPanoStack
 } from '@/env'
 
+const keyword = ref('')
+const filterTaggings = computed(() => taggings.value.filter(tagging => tagging.title.includes(keyword.value)))
 
 const editTagging = ref<Tagging | null>(null)
 const saveHandler = (tagging: Tagging) => {