|
@@ -3,6 +3,7 @@
|
|
|
<div class="furniture-rotated-container" :style="rotatedContainerStyle">
|
|
|
<div class="furniture-wrapper">
|
|
|
<furnitureIcon :icon="localItem.type" :width="localItem.width" :height="localItem.length" />
|
|
|
+ <span class="text"> {{ idx + 1 }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -11,12 +12,13 @@
|
|
|
<script setup lang="ts">
|
|
|
import { reactive, watch, computed, onMounted, nextTick, type CSSProperties } from 'vue'
|
|
|
import type { FurnitureItem, FurnitureType, LocalFurnitureItem } from '@/api/room/types'
|
|
|
-import { convert_furniture_r2c, rotateRect } from '@/utils/coordTransform'
|
|
|
+import { convert_furniture_r2c, rotateRect_cw } from '@/utils/coordTransform'
|
|
|
|
|
|
defineOptions({ name: 'EditableFurniture' })
|
|
|
|
|
|
interface Props {
|
|
|
item: FurnitureItem
|
|
|
+ idx: number
|
|
|
angle: number
|
|
|
coordinates: [number, number, number, number]
|
|
|
canvasSize?: number
|
|
@@ -118,33 +120,34 @@ const pixelPosition = reactive({ left: props.item.left ?? 0, top: props.item.top
|
|
|
const boundingBox = computed(() => calculateBoundingBox())
|
|
|
|
|
|
// 容器样式 - 基于边界框
|
|
|
-const containerStyle = computed(
|
|
|
- () =>
|
|
|
- ({
|
|
|
- position: 'absolute',
|
|
|
- left: `${pixelPosition.left}px`,
|
|
|
- top: `${pixelPosition.top}px`,
|
|
|
- width: `${boundingBox.value.width}px`,
|
|
|
- height: `${boundingBox.value.height}px`,
|
|
|
- pointerEvents: props.disabled ? 'none' : 'auto',
|
|
|
- zIndex: 100,
|
|
|
- cursor: 'move',
|
|
|
- }) as CSSProperties
|
|
|
-)
|
|
|
+const containerStyle = computed(() => {
|
|
|
+ const cssObj: CSSProperties = {
|
|
|
+ position: 'absolute',
|
|
|
+ left: `${pixelPosition.left}px`,
|
|
|
+ top: `${pixelPosition.top}px`,
|
|
|
+ width: `${boundingBox.value.width}px`,
|
|
|
+ height: `${boundingBox.value.height}px`,
|
|
|
+ pointerEvents: props.disabled ? 'none' : 'auto',
|
|
|
+ zIndex: 100,
|
|
|
+ }
|
|
|
+ console.log('💆♀️💆♀️💆♀️💆♀️ AAAAA containerStyle', cssObj)
|
|
|
+ return cssObj
|
|
|
+})
|
|
|
|
|
|
// 旋转容器样式 - 调整位置使左上角对齐
|
|
|
-const rotatedContainerStyle = computed(
|
|
|
- () =>
|
|
|
- ({
|
|
|
- position: 'absolute',
|
|
|
- left: `${-boundingBox.value.left}px`,
|
|
|
- top: `${-boundingBox.value.top}px`,
|
|
|
- width: `${localItem.width}px`,
|
|
|
- height: `${localItem.length}px`,
|
|
|
- transform: `rotate(${localItem.rotate}deg)`,
|
|
|
- transformOrigin: '0 0',
|
|
|
- }) as CSSProperties
|
|
|
-)
|
|
|
+const rotatedContainerStyle = computed(() => {
|
|
|
+ const cssObj: CSSProperties = {
|
|
|
+ position: 'absolute',
|
|
|
+ left: `${-boundingBox.value.left}px`,
|
|
|
+ top: `${-boundingBox.value.top}px`,
|
|
|
+ width: `${localItem.width}px`,
|
|
|
+ height: `${localItem.length}px`,
|
|
|
+ transform: `rotate(${localItem.rotate}deg)`,
|
|
|
+ transformOrigin: '0 0',
|
|
|
+ }
|
|
|
+ console.log('💆♀️💆♀️💆♀️💆♀️ BBBBB rotatedContainerStyle', cssObj)
|
|
|
+ return cssObj
|
|
|
+})
|
|
|
|
|
|
// 监听props变化
|
|
|
watch(
|
|
@@ -192,14 +195,16 @@ const updatePixelPosition = () => {
|
|
|
}
|
|
|
|
|
|
const initPixelPosition = () => {
|
|
|
- const { x, y, width, length } = props.item
|
|
|
+ const { x, y, width: itemLength, length: itemWidth } = props.item
|
|
|
+ // ⚠️ width: itemLength, length: itemWidth 回显时需要转换一下,不然家具会有偏移
|
|
|
+
|
|
|
// === 1️⃣ 将房间坐标转换为画布坐标 ===
|
|
|
const itemConvert = convert_furniture_r2c(
|
|
|
{
|
|
|
x: x,
|
|
|
y: y,
|
|
|
- width: width,
|
|
|
- height: length,
|
|
|
+ width: itemWidth,
|
|
|
+ height: itemLength,
|
|
|
},
|
|
|
{
|
|
|
x_radar: 250,
|
|
@@ -208,12 +213,12 @@ const initPixelPosition = () => {
|
|
|
)
|
|
|
|
|
|
// === 2️⃣ 再根据雷达朝向旋转 ===
|
|
|
- const rotatedRect = rotateRect(
|
|
|
+ const rotatedRect = rotateRect_cw(
|
|
|
{
|
|
|
left: itemConvert.left,
|
|
|
top: itemConvert.top,
|
|
|
- width: width,
|
|
|
- height: length,
|
|
|
+ width: itemConvert.width,
|
|
|
+ height: itemConvert.height,
|
|
|
},
|
|
|
{ x: 250, y: 250 },
|
|
|
props.angle
|
|
@@ -224,8 +229,8 @@ const initPixelPosition = () => {
|
|
|
pixelPosition.top = rotatedRect.top
|
|
|
|
|
|
// 同步像素位置到 localItem(方便 emit)
|
|
|
- localItem.left = rotatedRect.left
|
|
|
- localItem.top = rotatedRect.top
|
|
|
+ localItem.left = pixelPosition.left
|
|
|
+ localItem.top = pixelPosition.top
|
|
|
|
|
|
console.log('✅ Init pixel position (after convert & rotate):', {
|
|
|
angle: props.angle,
|
|
@@ -281,10 +286,21 @@ const startDrag = (e: MouseEvent) => {
|
|
|
const startY = e.clientY
|
|
|
const initLeft = pixelPosition.left
|
|
|
const initTop = pixelPosition.top
|
|
|
+ const canvasSize = props.canvasSize
|
|
|
|
|
|
const onMove = (ev: MouseEvent) => {
|
|
|
- pixelPosition.left = initLeft + (ev.clientX - startX)
|
|
|
- pixelPosition.top = initTop + (ev.clientY - startY)
|
|
|
+ // 计算新的位置
|
|
|
+ let newLeft = initLeft + (ev.clientX - startX)
|
|
|
+ let newTop = initTop + (ev.clientY - startY)
|
|
|
+
|
|
|
+ // 边界检查 - 确保家具不会超出画布
|
|
|
+ newLeft = Math.max(0, Math.min(newLeft, canvasSize - boundingBox.value.width))
|
|
|
+ newTop = Math.max(0, Math.min(newTop, canvasSize - boundingBox.value.height))
|
|
|
+
|
|
|
+ // 更新位置
|
|
|
+ pixelPosition.left = newLeft
|
|
|
+ pixelPosition.top = newTop
|
|
|
+
|
|
|
updateGeoPosition()
|
|
|
emit('update', { ...localItem })
|
|
|
}
|
|
@@ -323,10 +339,20 @@ const startDrag = (e: MouseEvent) => {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
+ position: relative;
|
|
|
|
|
|
:deep(*) {
|
|
|
pointer-events: none;
|
|
|
}
|
|
|
+
|
|
|
+ .text {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #f41313;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|