Sfoglia il codice sorgente

feat: 调整家具配置组件逻辑;

liujia 3 settimane fa
parent
commit
10b3bc9

+ 19 - 11
src/components/EditableFurniture/index.vue

@@ -2,7 +2,7 @@
   <div
     class="editable-furniture"
     :style="{
-      position: 'relative',
+      position: 'absolute',
       left: `${centerCss.left}px`,
       top: `${centerCss.top}px`,
       zIndex: 10,
@@ -34,11 +34,6 @@
         <div class="capsule" @mousedown.prevent="startPanelDrag"></div>
       </div>
 
-      <!-- <div class="panel-item">
-        <label>家具名称:</label>
-        <a-input v-model:value="localItem.name" size="small" />
-      </div> -->
-
       <div class="panel-item">
         <label>家具尺寸:</label>
         <a-space>
@@ -149,8 +144,6 @@ watch(
   () => props.item,
   (next) => {
     if (!next) return
-
-    // 显式解构预期要合并的字段
     const { x, y, width, length, rotate, name, type, nanoid, left, top } = next as Partial<UIItem>
 
     if (x !== undefined) localItem.x = x
@@ -163,6 +156,8 @@ watch(
     if (nanoid !== undefined) localItem.nanoid = nanoid
     if (left !== undefined) localItem.left = left
     if (top !== undefined) localItem.top = top
+
+    updateXYFromCss()
   },
   { deep: true }
 )
@@ -286,7 +281,6 @@ function setPanelInitialPosition() {
 }
 
 onMounted(() => {
-  // 使用父组件传入的业务左上角(若有)
   localItem.x = props.item.x ?? localItem.x
   localItem.y = props.item.y ?? localItem.y
   ;({ x: localItem.x, y: localItem.y } = normXY(localItem.x!, localItem.y!))
@@ -296,12 +290,26 @@ onMounted(() => {
     localItem.y = 0
   }
 
+  const hasLeftTopFromProps =
+    (props.item as Partial<UIItem>).left !== undefined &&
+    (props.item as Partial<UIItem>).top !== undefined
+
   nextTick()
     .then(() => new Promise<void>((r) => requestAnimationFrame(() => r())))
-    .then(() => updateCssFromXY())
+    .then(() => {
+      if (!hasLeftTopFromProps || props.initialAtOrigin) {
+        updateCssFromXY()
+      } else {
+        localItem.left = (props.item as Partial<UIItem>).left!
+        localItem.top = (props.item as Partial<UIItem>).top!
+        centerCss.left = localItem.left + (localItem.width ?? 0) / 2
+        centerCss.top = localItem.top + (localItem.length ?? 0) / 2
+      }
+
+      updateXYFromCss()
+    })
     .then(() => {
       setPanelInitialPosition()
-      // emit initial state with left/top populated
       emit('update', { ...localItem })
     })
 })

+ 3 - 1
src/components/RadarEditor/index.vue

@@ -1,7 +1,9 @@
 <template>
   <RadarView :coordinates="coordinates" :angle="angle">
-    <template v-for="item in localFurniture" :key="item.nanoid">
+    <template #furnitures>
       <EditableFurniture
+        v-for="item in localFurniture"
+        :key="item.nanoid"
         :item="item"
         :angle="angle"
         :coordinates="coordinates"

+ 51 - 50
src/components/RadarView/index.vue

@@ -14,61 +14,61 @@
       }"
       :draggable="false"
     />
-    <div class="furnitures">
-      <furniture-icon
-        v-for="item in filteredFurniture"
-        :key="item.nanoid"
-        :icon="item.type"
-        :width="item.width"
-        :height="item.length"
-        :style="{
-          left: `${item.left}px`,
-          top: `${item.top}px`,
-          position: 'absolute',
-          rotate: `${item.rotate}deg`,
-          cursor: 'default',
-        }"
-        :draggable="false"
-      />
+    <div class="furnitures" :style="{ overflow: !!slots.furnitures ? 'visible' : 'hidden' }">
+      <slot name="furnitures">
+        <furniture-icon
+          v-for="item in filteredFurniture"
+          :key="item.nanoid"
+          :icon="item.type"
+          :width="item.width"
+          :height="item.length"
+          :style="{
+            left: `${item.left}px`,
+            top: `${item.top}px`,
+            position: 'absolute',
+            rotate: `${item.rotate}deg`,
+            cursor: 'default',
+          }"
+          :draggable="false"
+        />
+      </slot>
     </div>
 
-    <div class="targets">
-      <template v-if="targets && Object.keys(targets).length > 0">
-        <template v-for="t in targets" :key="t.id">
-          <div
-            class="target-dot"
-            :style="{
-              position: 'absolute',
-              width: '18px',
-              height: '18px',
-              background: t.id === 0 ? 'red' : t.id === 1 ? 'blue' : 'green',
-              borderRadius: '50%',
-              transform: `translate3d(${t.displayX}px, ${-t.displayY!}px, 0) translate(-50%, -50%)`,
-              zIndex: 10,
-              transition: 'transform 1s linear',
-              willChange: 'transform',
-            }"
+    <div v-if="targets && Object.keys(targets).length > 0" class="targets">
+      <template v-for="t in targets" :key="t.id">
+        <div
+          class="target-dot"
+          :style="{
+            position: 'absolute',
+            width: '18px',
+            height: '18px',
+            background: t.id === 0 ? 'red' : t.id === 1 ? 'blue' : 'green',
+            borderRadius: '50%',
+            transform: `translate3d(${t.displayX}px, ${-t.displayY!}px, 0) translate(-50%, -50%)`,
+            zIndex: 10,
+            transition: 'transform 1s linear',
+            willChange: 'transform',
+          }"
+        >
+          <span
+            style="
+              color: #fff;
+              font-size: 12px;
+              font-weight: 600;
+              position: absolute;
+              left: 50%;
+              top: 50%;
+              transform: translate(-50%, -50%);
+              pointer-events: none;
+            "
           >
-            <span
-              style="
-                color: #fff;
-                font-size: 12px;
-                font-weight: 600;
-                position: absolute;
-                left: 50%;
-                top: 50%;
-                transform: translate(-50%, -50%);
-                pointer-events: none;
-              "
-            >
-              {{ t.id }}
-            </span>
-          </div>
-        </template>
+            {{ t.id }}
+          </span>
+        </div>
       </template>
     </div>
 
-    <div class="content"><slot /></div>
+    <!-- <div class="content"><slot /></div> -->
 
     <div v-if="showInfo" class="info-box">
       检测区域:{{ areaWidth }} × {{ areaHeight }} cm<br />
@@ -100,11 +100,12 @@
 </template>
 
 <script setup lang="ts">
-import { computed, ref, type CSSProperties } from 'vue'
+import { computed, ref, type CSSProperties, useSlots } from 'vue'
 import type { FurnitureItem, TargetPoint } from '@/types/radar'
 import { QuestionCircleOutlined } from '@ant-design/icons-vue'
 
 defineOptions({ name: 'RadarView' })
+const slots = useSlots()
 
 interface Props {
   coordinates: [number, number, number, number] // 坐标边界:[xStart, xEnd, yStart, yEnd]