From 33dbc6a161554f3a897f9e9273feb4f2c1b47381 Mon Sep 17 00:00:00 2001
From: chenlu <1320612696@qq.com>
Date: 星期一, 15 十二月 2025 17:04:27 +0800
Subject: [PATCH] Merge branch 'master' of http://10.153.19.25:10105/r/ERP_override

---
 north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/OptimizationRect.vue | 1371 ++++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 975 insertions(+), 396 deletions(-)

diff --git a/north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/OptimizationRect.vue b/north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/OptimizationRect.vue
index ea5170a..5a9490e 100644
--- a/north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/OptimizationRect.vue
+++ b/north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/OptimizationRect.vue
@@ -1,16 +1,80 @@
 <template>
-  <div style="display: flex; height: 100vh;">
+  <div style="display: flex; height: 90vh;">
     <!-- Sidebar -->
-    <div class="sidebar" style="width: 200px; background: #f4f4f4; padding: 10px;">
-      <div
-        v-for="(layout, layoutIndex) in layouts"
-        :key="layoutIndex"
-        class="sidebar-item"
-        @click="selectLayout(layoutIndex)"
-        :class="{ 'selected': selectedLayoutIndex === layoutIndex }"
-      >
-        {{ layout.width }} 脳 {{ layout.height }} 脳 {{ layout.SameCount }}
+    <div class="sidebar" style="width: 200px; background: #f4f4f4; padding: 10px; height: 93%; overflow-y: auto; max-height: 90vh; border-radius: 8px;">
+      <div class="folder">
+        <div
+          class="folder-header"          style="padding: 8px; background: #e0e0e0; margin-bottom: 5px; border-radius: 4px; user-select: none; display: flex; justify-content: space-between; align-items: center;"
+        >
+          <span @click="toggleFolder('pending')" style="flex: 1; cursor: pointer;">寰呭垏鍓插師鐗�</span>
+          <button
+            @click="toggleFolder('pending')"            style="background: none; border: none; cursor: pointer; font-size: 14px; padding: 2px 5px; border-radius: 3px;"
+            :title="openFolders.pending ? '鏀惰捣' : '灞曞紑'"
+          >
+            <el-icon v-if="openFolders.pending"><ArrowUp /></el-icon>
+            <el-icon v-else><ArrowDown /></el-icon>
+          </button>
+        </div>
+        <div v-show="openFolders.pending" class="folder-content" style="padding-left: 15px;">
+          <div
+            v-for="(layout, layoutIndex) in layouts"
+            :key="layoutIndex"
+            class="sidebar-item"
+            @click="selectLayout(layoutIndex)"
+            :class="{ 'selected': selectedLayoutIndex === layoutIndex }"            style="margin-bottom: 5px;"
+          >
+            {{ layout.realWidth }} 脳 {{ layout.realHeight }} 脳 {{ layout.quantity }}
+          </div>
+        </div>
       </div>
+
+<!-- 寰呰ˉ鐗囬槦鍒楁枃浠跺す -->
+      <div class="folder">
+        <div
+          class="folder-header"          style="padding: 8px; background: #e0e0e0; margin-bottom: 5px; border-radius: 4px; user-select: none; display: flex; justify-content: space-between; align-items: center;"
+        >
+          <span @click="toggleFolder('patchQueue')" style="flex: 1; cursor: pointer;">寰呰ˉ鐗囬槦鍒�</span>
+          <button
+            @click="toggleFolder('patchQueue')"            style="background: none; border: none; cursor: pointer; font-size: 14px; padding: 2px 5px; border-radius: 3px;"
+            :title="openFolders.patchQueue ? '鏀惰捣' : '灞曞紑'"
+          >
+            <el-icon v-if="openFolders.patchQueue"><ArrowUp /></el-icon>
+            <el-icon v-else><ArrowDown /></el-icon>
+          </button>
+        </div>
+        <div v-show="openFolders.patchQueue" class="folder-content" style="padding-left: 15px;">
+          <div style="padding: 10px; color: #666; font-style: italic;">
+            鏆傛棤琛ョ墖浠诲姟
+          </div>
+        </div>
+      </div>
+
+      <!-- 娣诲姞鑷畾涔夊昂瀵告枃浠跺す -->
+      <div class="folder">
+        <div
+          class="folder-header"          style="padding: 8px; background: #e0e0e0; margin-bottom: 5px; border-radius: 4px; user-select: none; display: flex; justify-content: space-between; align-items: center;"
+        >
+          <span @click="toggleFolder('customSize')" style="flex: 1; cursor: pointer;">娣诲姞鑷畾涔夊昂瀵�</span>
+          <button
+            @click="toggleFolder('customSize')"            style="background: none; border: none; cursor: pointer; font-size: 14px; padding: 2px 5px; border-radius: 3px;"
+            :title="openFolders.customSize ? '鏀惰捣' : '灞曞紑'"
+          >
+            <el-icon v-if="openFolders.customSize"><ArrowUp /></el-icon>
+            <el-icon v-else><ArrowDown /></el-icon>
+          </button>
+        </div>
+        <div v-show="openFolders.customSize" class="folder-content" style="padding-left: 15px;">
+          <div style="padding: 10px;">
+            <button
+              @click="showAddCustomSizeDialog"              style="width: 100%; padding: 8px; background: #409eff; color: white; border: none; border-radius: 4px; cursor: pointer;"
+            >
+              + 娣诲姞鑷畾涔夊昂瀵�
+            </button>
+          </div>
+        </div>
+      </div>
+
+
     </div>
 
     <!-- Main Layout Panel -->
@@ -27,42 +91,47 @@
         </div>
 
         <!-- Layout Container -->
+        <div class="layout-container" :style="layoutContainerStyle1(layoutIndex)">
         <div class="layout-container" :style="layoutContainerStyle(layoutIndex)">
           <!-- 鐏拌壊鐭╁舰 -->
           <div
-            v-for="(rect, rectIndex) in layout.rects.filter(r => r.isRemain)"
+            v-for="(glassDetail, rectIndex) in layout.glassDetails.filter(r => r.isRemain)"
             :key="`gray-${rectIndex}`"
             :ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
-            class="layout-rect"
-            :style="rectStyle(rect, layoutIndex)"
-            @contextmenu.prevent="handleGrayRectRightClick(layoutIndex, rectIndex)"
-          />
+            class="layout-glassDetail"
+            :style="rectStyle1(glassDetail, layoutIndex)"
+            @contextmenu.prevent="handleGrayRectRightClick(layoutIndex, rectIndex,glassDetail)"
+          >
+<!--            <div class="glassDetail-content">
+              <div class="size">{{ glassDetail.width }}脳{{ glassDetail.height }}</div>
+              <div v-if="showJiaHao" class="jia-hao">{{ glassDetail.JiaHao }}</div>
+              <div v-if="showProcessId" class="liuchengka">{{ glassDetail.liuchengka }}</div>
+            </div>-->
+          </div>
 
           <!-- 钃濊壊鐭╁舰 -->
           <div
-            v-for="(rect, rectIndex) in layout.rects.filter(r => !r.isRemain)"
+            v-for="(glassDetail, rectIndex) in layout.glassDetails.filter(r => !r.isRemain)"
             :key="`blue-${rectIndex}`"
             :ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
-            class="layout-rect"
-            :style="rectStyle(rect, layoutIndex)"
+            class="layout-glassDetail"
+            :style="rectStyle(glassDetail, layoutIndex)"
             @contextmenu.prevent="handleRectRightClick(layoutIndex, rectIndex)"
-            @mousedown="handleRectDragStart(layoutIndex, rectIndex)"
-            @mousemove="handleRectDragging"
-            @mouseup="handleRectDragEnd"
-            @mouseleave="handleRectDragEnd"
+            @click="handleRectClick(layoutIndex, rectIndex)"
           >
-            <div class="rect-content">
-              <div class="size">{{ rect.w }}脳{{ rect.h }}</div>
-              <div v-if="showJiaHao" class="jia-hao">{{ rect.JiaHao }}</div>
-              <div v-if="showProcessId" class="liuchengka">{{ rect.liuchengka }}</div>
+            <div class="glassDetail-content">
+              <div class="size">{{ glassDetail.realWidth }}脳{{ glassDetail.realHeight }}</div>
+              <div>{{glassDetail.polySort }}</div>
+              <div v-if="showJiaHao" class="jia-hao">{{ glassDetail.rackNo }}</div>
+              <div v-if="showProcessId" class="liuchengka">{{ glassDetail.processId }}</div>
             </div>
           </div>
+        </div>
         </div>
       </div>
     </div>
 
-    <!-- 鎻愪氦鎸夐挳 -->
-    <button @click="submitLayouts" style="position: fixed; bottom: 20px; right: 20px; padding: 10px; background: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer;">
+    <button @click="submitLayouts" style="position: fixed; top: 90px; right: 20px; padding: 10px; background: #409eff; color: white; border: none; border-radius: 5px; cursor: pointer;">
       淇濆瓨璋冩暣
     </button>
   </div>
@@ -70,7 +139,10 @@
 
 <script setup>
 import { ref, reactive, onMounted, onUnmounted } from 'vue';
+import { useRouter } from 'vue-router';
+import { ArrowUp, ArrowDown } from '@element-plus/icons-vue'
 import request from "@/utils/request";
+const router = useRouter();
 import { useI18n } from "vue-i18n";
 import { ElMessage, ElMessageBox } from "element-plus";
 import useUserInfoStore from "@/stores/userInfo";
@@ -78,8 +150,7 @@
 const { t } = useI18n();
 const userStore = useUserInfoStore()
 const username = userStore.user.userName
-
-
+let clickEventListener = null;
 const props = defineProps({
   layoutData: { type: Object, required: true },
   gw: { type: Number, default: 1000 },
@@ -92,45 +163,83 @@
 const rectsElements = ref({});
 const focusIndex = ref(null);
 const layouts = ref([]);
+const layoutsHead = ref();
 const panelClass = ref('');
 const panelStyle = ref(props.style);
-const rectClass = ref('layout-rect');
+const rectClass = ref('layout-glassDetail');
 const selectedLayoutIndex = ref(0);
 const currentRect = ref(null);
-const dragging = ref(false);
-const dragStartPos = ref({ x: 0, y: 0 });
-const dragRect = ref(null);
-const showJiaHao = ref(false); // 鏂板锛氭帶鍒秊ia-hao鐨勬樉绀虹姸鎬�
-const showProcessId= ref(false);
-const themeColor=ref(null)
-// 鎻愪氦甯冨眬鏁版嵁鍒板悗绔�
+// const dragging = ref(false);
+// const dragStartPos = ref({ x: 0, y: 0 });
+// const dragRect = ref(null);
+const showJiaHao = ref(false);
+const showProcessId = ref(false);
+const themeColor = ref(null);
+
+//淇濆瓨璋冩暣
 const submitLayouts = async () => {
   layouts.value.forEach(layout => {
-    layout.rects.forEach(rect => {
-      rect.x = Math.round(rect.x);
-      rect.y = Math.round(rect.y);
-      rect.w = Math.round(rect.w);
-      rect.h = Math.round(rect.h);
+    layout.glassDetails.forEach(glassDetail => {
+      glassDetail.x = parseFloat(glassDetail.x.toFixed(2));
+      glassDetail.y = parseFloat(glassDetail.y.toFixed(2));
+      glassDetail.width = parseFloat(glassDetail.width.toFixed(2));
+      glassDetail.height = parseFloat(glassDetail.height.toFixed(2));
     });
   });
   const savedProjectNo = localStorage.getItem('projectNo');
   const processId = savedProjectNo;
-  const Layouts = layouts.value;
-  request.post(`/glassOptimize/updateOptimizeResult/${processId}`, JSON.stringify({ Layouts }), {
+  // 鏋勯�犱笌鍘熷鏁版嵁缁撴瀯涓�鑷寸殑瀵硅薄
+  const saveData = {
+    projectNo: processId,
+    layouts: layouts.value,
+    // 澶嶅埗鍘熷鏁版嵁涓殑鍏朵粬蹇呰瀛楁
+    ...layoutsHead.value
+  };
+
+  // 纭繚 Layouts 瀛楁鏄簭鍒楀寲鐨勫瓧绗︿覆
+  const requestData = {
+    Layouts: JSON.stringify(saveData)
+  };
+  request.post(`/glassOptimize/updateOptimizeResult/${processId}`, layoutsHead.value, {
     headers: {
       'Content-Type': 'application/json'
     }
   }).then((res) => {
     if (res.code == 200 && res.data === true) {
       ElMessage.success(t('basicData.msg.saveSuccess'));
+      // // 淇濆瓨鎴愬姛鍚庤烦杞埌鏁版帶鐣岄潰
+      // router.push({ path: '/main/glassOptimize/OptimizeControl' });
     } else {
       ElMessage.warning(res.msg);
     }
   });
 };
 
+const openFolders = ref({
+  pending: true,  // 榛樿灞曞紑"寰呭垏鍓插師鐗�"鏂囦欢澶�
+   patchQueue: false,   // 榛樿鏀惰捣"寰呰ˉ鐗囬槦鍒�"鏂囦欢澶�
+  customSize: false   // 榛樿鏀惰捣"娣诲姞鑷畾涔夊昂瀵�"鏂囦欢澶�
+});
 
-//鑾峰彇浼樺寲璁剧疆
+// 鍒囨崲鏂囦欢澶瑰睍寮�/鏀惰捣鐘舵��
+const toggleFolder = (folderName) => {
+  openFolders.value[folderName] = !openFolders.value[folderName];
+};
+
+
+
+const showAddCustomSizeDialog = () => {
+  // 妫�鏌ユ槸鍚﹂�夋嫨浜嗙増鍥�
+  if (selectedLayoutIndex.value === null || layouts.value.length === 0) {
+    ElMessage.warning('璇峰厛閫夋嫨涓�涓増鍥�');
+    return;
+  }
+
+  // 浣跨敤鐜版湁鐨勬坊鍔犳垚鍝侀�昏緫锛屼紶鍏ュ綋鍓嶉�変腑鐨勭増鍥剧储寮�
+  showAddDialog(selectedLayoutIndex.value);
+};
+
+//鏌ヨ璁剧疆鐨勫熀纭�淇℃伅鏋跺彿锛岀煩褰㈤鑹诧紝璁㈠崟搴忓彿绛�
 const fetchSettings = async (username) => {
   try {
     const response = await request.post(`/glassOptimize/selectOptimizeParms/${username}`);
@@ -140,23 +249,15 @@
         return;
       }
       const parsedData = JSON.parse(response.data);
-      console.log(parsedData.display.frameNumber)
-      if (parsedData.display && parsedData.display.frameNumber) {
+      if (parsedData.display && parsedData.frameNumber) {
         showJiaHao.value = parsedData.display.frameNumber;
-
       }
-      if (parsedData.display && parsedData.display.orderNumber) {
+      if (parsedData.display && parsedData.orderNumber) {
         showProcessId.value = parsedData.display.orderNumber;
-      
       }
-      if (parsedData.display ) {
+      if (parsedData.display) {
         themeColor.value = parsedData.display.themeColor;
-      
       }
-      
-      
-      
-      console.log( parsedData);
     } else {
       console.error('璇锋眰澶辫触锛岀姸鎬佺爜:', response.code);
     }
@@ -165,8 +266,7 @@
   }
 };
 
-
-
+//娣诲姞鎴愬搧
 const showAddDialog = (layoutIndex, rectIndex) => {
   ElMessageBox.prompt('璇疯緭鍏ユ垚鍝佺殑瀹藉害鍜岄珮搴�', '娣诲姞鎴愬搧', {
     inputType: 'text',
@@ -186,93 +286,184 @@
     },
     inputErrorMessage: '杈撳叆鏍煎紡涓嶆纭�'
   })
-  .then(({ value }) => {
-    const values = value.split(',').map(v => parseFloat(v.trim()));
-    const newRect = {
-      x: 0,
-      y: 0,
-      w: values[0],
-      h: values[1],
-      isRemain: false
-     
-    };
-    addNewRect(layoutIndex, newRect);
-  })
-  .catch(() => {
-    // 鐢ㄦ埛鍙栨秷
-  });
+    .then(({ value }) => {
+      const values = value.split(',').map(v => parseFloat(v.trim()));
+      const newRect = {
+        x: 0,
+        y: 0,
+        width: values[0],
+        height: values[1],
+        isRemain: false
+      };
+      addNewRect(layoutIndex, newRect);
+    })
+    .catch(() => {
+      // 鐢ㄦ埛鍙栨秷
+    });
 };
 
+//娣诲姞鎴愬搧閫昏緫鍒ゆ柇
 const addNewRect = (layoutIndex, newRect) => {
   const layout = layouts.value[layoutIndex];
-  layout.rects.push(newRect);
-  adjustGrayRectangles(layoutIndex);
+  const bestFitPosition = findBestFitPosition(layoutIndex, newRect);
+  if (bestFitPosition) {
+    newRect.x = bestFitPosition.x;
+    newRect.y = bestFitPosition.y;
+    layout.glassDetails.push(newRect);
+    adjustGrayRectangles(layoutIndex);
+  } else {
+    ElMessage.warning('鏃犳硶鏀剧疆锛屾病鏈夎冻澶熺殑绌洪棿');
+  }
 };
 
-const layoutContainerStyle = (layoutIndex) => {
-  const containerWidth = (props.gw - 210) / 2;
-  const containerHeight = (props.gh - 100) / 3;
+//娣诲姞鎴愬搧鍒ゆ柇鏄惁鍙互鏀句笅
+const findBestFitPosition = (layoutIndex, newRect) => {
   const layout = layouts.value[layoutIndex];
-  const scale = Math.min(
-    (props.gw - 100) / layout.width,
-    (props.gh - 100) / layout.height
+  const obstacles = layout.glassDetails.filter(r => !r.isRemain);
+  let bestFit = null;
+  let minAreaDifference = Infinity;
+
+  const remainingAreas = calculateRemainingAreas(layout.width, layout.height, obstacles);
+  remainingAreas.forEach(area => {
+    if (newRect.width <= area.width && newRect.height <= area.height) {
+      const areaDifference = Math.abs(area.width * area.height - newRect.width * newRect.height);
+      if (areaDifference < minAreaDifference) {
+        minAreaDifference = areaDifference;
+        bestFit = {
+          x: area.x,
+          y: area.y,
+          width: newRect.width,
+          height: newRect.height
+        };
+      }
+    }
+  });
+
+  return bestFit;
+};
+
+const isSelected = (layoutIndex, rectIndex) => {
+  return focusIndex.value &&
+         focusIndex.value.layoutIndex === layoutIndex &&
+         focusIndex.value.rectIndex === rectIndex;
+};
+
+//鐗堝浘鍐呭鏍峰紡鍔犺浇
+const layoutContainerStyle = (layoutIndex) => {
+  const layout = layouts.value[layoutIndex];
+  const scale = Math.min(0.25
   );
   return {
     position: 'absolute',
-    left: `${(props.gw - layout.width * scale) / 2}px`,
-    top: `${(props.gh - layout.height * scale) / 2}px`,
+    left: `${layout.leftTrim * scale}px`,
+    bottom: `${layout.upTrim * scale}px`,
     width: `${layout.width * scale}px`,
     height: `${layout.height * scale}px`,
     overflow: 'visible',
-    border: '1px solid #ccc',
+    //border: '1px solid #ccc',
     background: '#fff'
   };
 };
 
-const layoutInfoStyle = (layoutIndex) => {
+const layoutContainerStyle1 = (layoutIndex) => {
   const layout = layouts.value[layoutIndex];
-  const scale = Math.min(
-    (props.gw - 100) / layout.width,
-    (props.gh - 100) / layout.height
+  const scale = Math.min(0.25
   );
   return {
     position: 'absolute',
-    left: `${(props.gw - layout.width * scale) / 2}px`,
-    top: `${(props.gh - layout.height * scale) / 2 - 45}px`,
+    left: `20px`,
+    top: `140px`,
+    width: `${layout.realWidth * scale}px`,
+    height: `${layout.realHeight * scale}px`,
+    overflow: 'visible',
+    //border: '1px solid #ccc',
+    background: '#fff'
+  };
+};
+
+//鐗堝浘鍐呭澶撮儴鏍峰紡鍔犺浇
+const layoutInfoStyle = (layoutIndex) => {
+  const layout = layouts.value[layoutIndex];
+  const scale = Math.min(0.25
+  );
+  return {
+    position: 'absolute',
+    left: `20px`,
+    top: `100px`,
     background: 'none',
     textAlign: 'center',
     zIndex: 1000
   };
 };
 
-const rectStyle = (rect, layoutIndex) => {
+//鐗堝浘鍐呭灏忕墖鏍峰紡鍔犺浇
+const rectStyle = (glassDetail, layoutIndex) => {
   const layout = layouts.value[layoutIndex];
-  const scale = Math.min(
-    (props.gw - 100) / layout.width,
-    (props.gh - 100) / layout.height
-  );
-  return {
+  const scale = Math.min(0.25);
+  const isSelectedRect = isSelected(layoutIndex, layout.glassDetails.indexOf(glassDetail));
+
+  let style = {
     position: 'absolute',
-    left: `${rect.x * scale}px`,
-    top: `${rect.y * scale}px`,
-    width: `${rect.w * scale}px`,
-    height: `${rect.h * scale}px`,
-    backgroundColor: rect.isRemain ? '#f0f0f0' : themeColor.value,
+    left: `${glassDetail.x * scale}px`,
+    top: `${glassDetail.y * scale}px`,
+    width: `${glassDetail.width * scale}px`,
+    height: `${glassDetail.height * scale}px`,
+    backgroundColor: glassDetail.isRemain ? '#f0f0f0' : themeColor.value,
     border: '1px solid #000',
     cursor: 'pointer',
-    draggable: !rect.isRemain,
-    zIndex: rect.isRemain ? 1 : 2
+    draggable: !glassDetail.isRemain,
+    zIndex: glassDetail.isRemain ? 1 : 2
   };
+
+  // 濡傛灉琚�変腑锛屽垯娣诲姞鍐呬晶绾㈡
+  if (isSelectedRect) {
+    style.boxShadow = 'inset 0 0 0 2px red';
+  }
+
+  return style;
 };
 
+const rectStyle1 = (glassDetail, layoutIndex) => {
+  const layout = layouts.value[layoutIndex];
+  const scale = Math.min(0.25);
+  const isSelectedRect = isSelected(layoutIndex, layout.glassDetails.indexOf(glassDetail));
+
+  let style = {
+    position: 'absolute',
+    left: `${glassDetail.x * scale}px`,
+    top: `${glassDetail.y * scale}px`,
+    width: `${glassDetail.width * scale}px`,
+    height: `${glassDetail.height * scale}px`,
+    backgroundColor: glassDetail.isRemain ? '#f0f0f0' : themeColor.value,
+    border: '1px solid #000',
+    cursor: 'pointer',
+    draggable: !glassDetail.isRemain,
+    zIndex: glassDetail.isRemain ? 1 : 2
+  };
+
+  // 濡傛灉琚�変腑锛屽垯娣诲姞鍐呬晶绾㈡
+  if (isSelectedRect) {
+    style.boxShadow = 'inset 0 0 0 2px red';
+  }
+
+  return style;
+};
+
+//鐐瑰嚮灏忕墖
 const handleRectClick = (layoutIndex, rectIndex) => {
+  // if (dragging.value) {
+  //   return;
+  // }
+
   focusIndex.value = { layoutIndex, rectIndex };
   emit('rectClicked', layoutIndex, rectIndex);
 };
 
+//灏忕墖鍙抽敭鑿滃崟鍔熻兘
 const handleRectRightClick = (layoutIndex, rectIndex) => {
-  const rect = layouts.value[layoutIndex].rects[rectIndex];
-  if (rect.isRemain) return;
+  const glassDetail = layouts.value[layoutIndex].glassDetails[rectIndex];
+  if (glassDetail.isRemain) return;
+  document.querySelectorAll('.context-menu').forEach(el => el.remove());
 
   const contextMenu = document.createElement('div');
   contextMenu.className = 'context-menu';
@@ -296,7 +487,7 @@
   moveUpAndRotateItem.textContent = '鍚戜笂绉诲姩骞舵棆杞�';
   moveUpAndRotateItem.style.cursor = 'pointer';
   moveUpAndRotateItem.addEventListener('click', () => {
-    moveRectAndRotate(layoutIndex, rectIndex, 'up');
+    moveRectAndRotate(layoutIndex, rectIndex, 'down');
     document.body.removeChild(contextMenu);
   });
 
@@ -304,7 +495,7 @@
   moveDownAndRotateItem.textContent = '鍚戜笅绉诲姩骞舵棆杞�';
   moveDownAndRotateItem.style.cursor = 'pointer';
   moveDownAndRotateItem.addEventListener('click', () => {
-    moveRectAndRotate(layoutIndex, rectIndex, 'down');
+    moveRectAndRotate(layoutIndex, rectIndex, 'up');
     document.body.removeChild(contextMenu);
   });
 
@@ -328,7 +519,7 @@
   moveUpItem.textContent = '鍚戜笂绉诲姩';
   moveUpItem.style.cursor = 'pointer';
   moveUpItem.addEventListener('click', () => {
-    moveRect(layoutIndex, rectIndex, 'up');
+    moveRect(layoutIndex, rectIndex, 'down');
     document.body.removeChild(contextMenu);
   });
 
@@ -336,7 +527,7 @@
   moveDownItem.textContent = '鍚戜笅绉诲姩';
   moveDownItem.style.cursor = 'pointer';
   moveDownItem.addEventListener('click', () => {
-    moveRect(layoutIndex, rectIndex, 'down');
+    moveRect(layoutIndex, rectIndex, 'up');
     document.body.removeChild(contextMenu);
   });
 
@@ -372,6 +563,22 @@
     document.body.removeChild(contextMenu);
   });
 
+  const mirrorXItem = document.createElement('div');
+  mirrorXItem.textContent = 'X闀滃儚';
+  mirrorXItem.style.cursor = 'pointer';
+  mirrorXItem.addEventListener('click', () => {
+    mirrorLayoutX(layoutIndex);
+    document.body.removeChild(contextMenu);
+  });
+
+  const mirrorYItem = document.createElement('div');
+  mirrorYItem.textContent = 'Y闀滃儚';
+  mirrorYItem.style.cursor = 'pointer';
+  mirrorYItem.addEventListener('click', () => {
+    mirrorLayoutY(layoutIndex);
+    document.body.removeChild(contextMenu);
+  });
+
   contextMenu.appendChild(rotateItem);
   contextMenu.appendChild(moveUpAndRotateItem);
   contextMenu.appendChild(moveDownAndRotateItem);
@@ -383,13 +590,17 @@
   contextMenu.appendChild(moveRightItem);
   contextMenu.appendChild(deleteItem);
   contextMenu.appendChild(addItem);
+  contextMenu.appendChild(mirrorXItem);
+  contextMenu.appendChild(mirrorYItem);
 
   document.body.appendChild(contextMenu);
 };
 
-const handleGrayRectRightClick = (layoutIndex, rectIndex) => {
-  const rect = layouts.value[layoutIndex].rects[rectIndex];
-  if (!rect.isRemain) return;
+//浣欐枡鍙抽敭鑿滃崟鍔熻兘
+const handleGrayRectRightClick = (layoutIndex, rectIndex,glassDetails) => {
+  //const glassDetail = glassDetails[rectIndex];
+  if (!glassDetails.isRemain) return;
+  document.querySelectorAll('.context-menu').forEach(el => el.remove());
 
   const contextMenu = document.createElement('div');
   contextMenu.className = 'context-menu';
@@ -409,453 +620,805 @@
     document.body.removeChild(contextMenu);
   });
 
+  const mirrorXItem = document.createElement('div');
+  mirrorXItem.textContent = 'X闀滃儚';
+  mirrorXItem.style.cursor = 'pointer';
+  mirrorXItem.addEventListener('click', () => {
+    mirrorLayoutX(layoutIndex);
+    document.body.removeChild(contextMenu);
+  });
+
+  const mirrorYItem = document.createElement('div');
+  mirrorYItem.textContent = 'Y闀滃儚';
+  mirrorYItem.style.cursor = 'pointer';
+  mirrorYItem.addEventListener('click', () => {
+    mirrorLayoutY(layoutIndex);
+    document.body.removeChild(contextMenu);
+  });
+
   contextMenu.appendChild(addItem);
+  contextMenu.appendChild(mirrorXItem);
+  contextMenu.appendChild(mirrorYItem);
 
   document.body.appendChild(contextMenu);
 };
 
-const handleRectDragStart = (layoutIndex, rectIndex) => {
-  const layout = layouts.value[layoutIndex];
-  const rect = layout.rects[rectIndex];
-  if (rect.isRemain) return;
+//灏忕墖榧犳爣鎸変笅浜嬩欢
+// const handleRectDragStart = (layoutIndex, rectIndex) => {
+//   const layout = layouts.value[layoutIndex];
+//   const glassDetail = layout.glassDetails[rectIndex];
+//   if (glassDetail.isRemain) return;
+//
+//   dragRect.value = { layoutIndex, rectIndex };
+//   dragStartPos.value = {
+//     x: event.clientX,
+//     y: event.clientY
+//   };
+// };
 
-  dragging.value = true;
-  dragRect.value = { layoutIndex, rectIndex };
-  dragStartPos.value = {
-    x: event.clientX,
-    y: event.clientY
-  };
-};
+// //灏忕墖榧犳爣绉诲姩浜嬩欢
+// const handleRectDragging = (event) => {
+//   if (!dragRect.value) return;
+//
+//   // 濡傛灉杩樻病纭鏄嫋鎷斤紝鍒欏厛鍒ゆ柇鏄惁杈惧埌鎷栨嫿闃堝��(渚嬪5鍍忕礌)
+//   if (!dragging.value) {
+//     const deltaX = event.clientX - dragStartPos.value.x;
+//     const deltaY = event.clientY - dragStartPos.value.y;
+//     const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+//
+//     // 濡傛灉绉诲姩璺濈灏忎簬闃堝�硷紝鍒欒涓烘槸鐐瑰嚮鑰岄潪鎷栨嫿
+//     if (distance < 5) {
+//       return;
+//     }
+//
+//     // 杈惧埌闃堝�硷紝纭鏄嫋鎷芥搷浣�
+//     dragging.value = true;
+//   }
+//
+//   const layoutIndex = dragRect.value.layoutIndex;
+//   const rectIndex = dragRect.value.rectIndex;
+//   const layout = layouts.value[layoutIndex];
+//   const glassDetail = layout.glassDetails[rectIndex];
+//
+//   // 淇濆瓨鍘熷鍧愭爣鐢ㄤ簬璁$畻鍋忕Щ閲�
+//   const originalX = glassDetail.x;
+//   const originalY = glassDetail.y;
+//
+//   const scale = Math.min(
+//     (props.gw - 100) / layout.width,
+//     (props.gh - 100) / layout.height
+//   );
+//
+//   const deltaX = event.clientX - dragStartPos.value.x;
+//   const deltaY = event.clientY - dragStartPos.value.y;
+//
+//   const newRect = { ...glassDetail };
+//   newRect.x += deltaX / scale;
+//   newRect.y += deltaY / scale;
+//
+//   const otherRects = layout.glassDetails.filter(r => !r.isRemain && r !== glassDetail);
+//   let isValidMove = true;
+//
+//   otherRects.forEach(otherRect => {
+//     if (checkOverlap(newRect, otherRect)) {
+//       isValidMove = false;
+//     }
+//   });
+//
+//   if (newRect.x < 0 || newRect.y < 0 ||
+//       newRect.x + newRect.width > layout.width ||
+//       newRect.y + newRect.height > layout.height) {
+//     isValidMove = false;
+//   }
+//
+//   if (isValidMove) {
+//     glassDetail.x = newRect.x;
+//     glassDetail.y = newRect.y;
+//
+//     // 鏇存柊glassPoint鍧愭爣
+//     if (glassDetail.glassPoint && Array.isArray(glassDetail.glassPoint)) {
+//       const offsetX = glassDetail.x - originalX;
+//       const offsetY = glassDetail.y - originalY;
+//
+//       glassDetail.glassPoint.forEach(point => {
+//         point.X += offsetX;
+//         point.Y += offsetY;
+//         // 娣诲姞绮惧害鎺у埗
+//         point.X = parseFloat(point.X.toFixed(2));
+//         point.Y = parseFloat(point.Y.toFixed(2));
+//       });
+//     }
+//
+//     dragStartPos.value = {
+//       x: event.clientX,
+//       y: event.clientY
+//     };
+//     adjustGrayRectangles(layoutIndex);
+//   }
+// };
 
-const handleRectDragging = (event) => {
-  if (!dragging.value || !dragRect.value) return;
-
-  const layoutIndex = dragRect.value.layoutIndex;
-  const rectIndex = dragRect.value.rectIndex;
-  const layout = layouts.value[layoutIndex];
-  const rect = layout.rects[rectIndex];
-  const scale = Math.min(
-    (props.gw - 100) / layout.width,
-    (props.gh - 100) / layout.height
-  );
-
-  const deltaX = event.clientX - dragStartPos.value.x;
-  const deltaY = event.clientY - dragStartPos.value.y;
-
-  // 鍙皟鏁翠綅缃紝涓嶈皟鏁村ぇ灏�
-  const newRect = { ...rect };
-  newRect.x += deltaX / scale;
-  newRect.y += deltaY / scale;
-
-  // 妫�鏌ユ槸鍚︿笌鍏朵粬钃濊壊鐭╁舰閲嶅彔
-  const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
-  let isValidMove = true;
-  
-  otherRects.forEach(otherRect => {
-    if (checkOverlap(newRect, otherRect)) {
-      isValidMove = false;
-    }
-  });
-
-  // 妫�鏌ユ槸鍚﹁秴鍑哄竷灞�杈圭晫
-  if (newRect.x < 0 || newRect.y < 0 ||
-      newRect.x + newRect.w > layout.width ||
-      newRect.y + newRect.h > layout.height) {
-    isValidMove = false;
-  }
-
-  if (isValidMove) {
-    rect.x = newRect.x;
-    rect.y = newRect.y;
-    dragStartPos.value = {
-      x: event.clientX,
-      y: event.clientY
-    };
-    adjustGrayRectangles(layoutIndex);
-  }
-};
-
-const handleRectDragEnd = () => {
-  if (dragRect.value) {
-    const layoutIndex = dragRect.value.layoutIndex;
-    const rectIndex = dragRect.value.rectIndex;
-    const rect = layouts.value[layoutIndex].rects[rectIndex];
-    const layout = layouts.value[layoutIndex];
-    const scale = Math.min(
-      (props.gw - 100) / layout.width,
-      (props.gh - 100) / layout.height
-    );
-
-    // 鎷栧姩缁撴潫鍚庤嚜鍔ㄥ榻愬埌鏈�杩戠殑鏁存暟浣嶇疆
-    rect.x = Math.round(rect.x);
-    rect.y = Math.round(rect.y);
-
-    // 鍙皟鏁翠綅缃榻愶紝涓嶈皟鏁村ぇ灏�
-    adjustAlignmentPosition(layoutIndex, rectIndex);
-
-    // 璋冩暣鐏拌壊鐭╁舰
-    adjustGrayRectangles(layoutIndex);
-  }
-
-  dragging.value = false;
-  dragRect.value = null;
-};
+// //灏忕墖榧犳爣鏉惧紑浜嬩欢
+// const handleRectDragEnd = () => {
+//   dragging.value = false;
+//   dragRect.value = null;
+//   dragStartPos.value = { x: 0, y: 0 };
+//   if (dragRect.value) {
+//     const layoutIndex = dragRect.value.layoutIndex;
+//     const rectIndex = dragRect.value.rectIndex;
+//     const glassDetail = layouts.value[layoutIndex].glassDetails[rectIndex];
+//     const layout = layouts.value[layoutIndex];
+//     const scale = Math.min(
+//       (props.gw - 100) / layout.width,
+//       (props.gh - 100) / layout.height
+//     );
+//
+//     glassDetail.x = parseFloat(glassDetail.x.toFixed(2));
+//     glassDetail.y = parseFloat(glassDetail.y.toFixed(2));
+//     adjustAlignmentPosition(layoutIndex, rectIndex);
+//   }
+//
+//   dragging.value = false;
+//   dragRect.value = null;
+// };
 
 const adjustAlignmentPosition = (layoutIndex, rectIndex) => {
   const layout = layouts.value[layoutIndex];
-  const rect = layout.rects[rectIndex];
-  const otherRects = layout.rects.filter((r, i) => i !== rectIndex);
+  const glassDetail = layout.glassDetails[rectIndex];
+  const otherRects = layout.glassDetails.filter((r, i) => i !== rectIndex);
 
-  const threshold = Math.max(rect.w, rect.h) * 0.1;
+  const threshold = Math.max(glassDetail.width, glassDetail.height) * 0.1;
 
   otherRects.forEach(otherRect => {
-    if (Math.abs(rect.x - otherRect.x) < threshold) {
-      rect.x = Math.round((rect.x + otherRect.x) / 2);
+    // 姘村钩瀵归綈
+    if (Math.abs(glassDetail.x - otherRect.x) < threshold) {
+      glassDetail.x = Math.round((glassDetail.x + otherRect.x) / 2);
     }
-    if (Math.abs((rect.x + rect.w) - (otherRect.x + otherRect.w)) < threshold) {
-      // 涓嶈皟鏁村搴�
+    // 姘村钩瀵归綈鍙充晶杈圭紭
+    if (Math.abs((glassDetail.x + glassDetail.width) - (otherRect.x + otherRect.width)) < threshold) {
+      glassDetail.x = Math.round((otherRect.x + otherRect.width - glassDetail.width));
     }
-    if (Math.abs(rect.y - otherRect.y) < threshold) {
-      rect.y = Math.round((rect.y + otherRect.y) / 2);
+    // 鍨傜洿瀵归綈
+    if (Math.abs(glassDetail.y - otherRect.y) < threshold) {
+      glassDetail.y = Math.round((glassDetail.y + otherRect.y) / 2);
     }
-    if (Math.abs((rect.y + rect.h) - (otherRect.y + otherRect.h)) < threshold) {
-      // 涓嶈皟鏁撮珮搴�
+    // 鍨傜洿瀵归綈涓婅竟缂�
+    if (Math.abs((glassDetail.y + glassDetail.height) - (otherRect.y + otherRect.height)) < threshold) {
+      glassDetail.y = Math.round((otherRect.y + otherRect.height - glassDetail.height));
     }
   });
+
+  // 纭繚鐭╁舰涓嶄細瓒呭嚭甯冨眬杈圭晫
+  glassDetail.x = Math.max(0, glassDetail.x);
+  glassDetail.y = Math.max(0, glassDetail.y);
+  glassDetail.x = Math.min(glassDetail.x, layout.width - glassDetail.width);
+  glassDetail.y = Math.min(glassDetail.y, layout.height - glassDetail.height);
+
+  // 璋冩暣鍚庨噸鏂拌绠楃伆鑹蹭綑鏂�
+  adjustGrayRectangles(layoutIndex);
 };
 
-const mergeAdjacentGrayRects = (rects) => {
-  const grayRects = rects.filter(r => r.isRemain);
-  let merged = [];
-  
+const mergeAdjacentGrayRects = (glassDetails, totalWidth, totalHeight) => {
+  const grayRects = glassDetails.filter(r => r.isRemain);
+  const nonGrayRects = glassDetails.filter(r => !r.isRemain);
+
+  // 鎸夊潗鏍囨帓搴忥紝浼樺厛鎸墆鍧愭爣锛屽叾娆℃寜x鍧愭爣锛堣繖鏍锋洿绗﹀悎浠庝笂鍒颁笅銆佷粠宸﹀埌鍙崇殑闃呰涔犳儻锛�
   grayRects.sort((a, b) => {
-    if (a.x !== b.x) return a.x - b.x;
-    return a.y - b.y;
+    if (a.y !== b.y) return a.y - b.y;
+    return a.x - b.x;
   });
 
   if (grayRects.length === 0) return;
 
-  merged.push({ ...grayRects[0] });
+  const merged = [];
+  let current = { ...grayRects[0] };
 
+  // 閬嶅巻鎵�鏈変綑鏂欑煩褰㈣繘琛屽悎骞�
   for (let i = 1; i < grayRects.length; i++) {
-    const last = merged[merged.length - 1];
-    const current = grayRects[i];
+    const next = grayRects[i];
 
-    if (current.x === last.x + last.w && 
-        current.y === last.y && 
-        current.h === last.h) {
-      last.w += current.w;
-      last.x = Math.round(last.x);
-      last.y = Math.round(last.y);
-      last.w = Math.round(last.w);
-      last.h = Math.round(last.h);
-    } else if (current.y === last.y + last.h && 
-               current.x === last.x && 
-               current.w === last.w) {
-      last.h += current.h;
-      last.x = Math.round(last.x);
-      last.y = Math.round(last.y);
-      last.w = Math.round(last.w);
-      last.h = Math.round(last.h);
-    } else {
-      merged.push({ 
-        x: Math.round(current.x),
-        y: Math.round(current.y),
-        w: Math.round(current.w),
-        h: Math.round(current.h),
+    // 妫�鏌ユ槸鍚﹀彲浠ユ按骞冲悎骞讹紙鍚屼竴琛岋紝楂樺害鐩稿悓锛岀浉閭伙級
+    if (current.y === next.y &&
+        current.height === next.height &&
+        current.x + current.width === next.x) {
+      // 姘村钩鍚堝苟
+      current.width += next.width;
+    }
+    // 妫�鏌ユ槸鍚﹀彲浠ュ瀭鐩村悎骞讹紙鍚屼竴鍒楋紝瀹藉害鐩稿悓锛岀浉閭伙級
+    else if (current.x === next.x &&
+        current.width === next.width &&
+        current.y + current.height === next.y) {
+      // 鍨傜洿鍚堝苟
+      current.height += next.height;
+    }
+    else {
+      // 鏃犳硶鍚堝苟锛屼繚瀛樺綋鍓嶇煩褰紝寮�濮嬫柊鐨勫悎骞�
+      merged.push({
+        x: current.x,
+        y: current.y,
+        width: current.width,
+        height: current.height,
         isRemain: true
       });
+      current = { ...next };
     }
   }
 
-  const nonGray = rects.filter(r => !r.isRemain);
-  rects.splice(0, rects.length, ...nonGray, ...merged);
+  // 娣诲姞鏈�鍚庝竴涓煩褰�
+  merged.push({
+    x: current.x,
+    y: current.y,
+    width: current.width,
+    height: current.height,
+    isRemain: true
+  });
+
+  // 閲嶆柊鏋勫缓鏁扮粍锛氶潪浣欐枡 + 鍚堝苟鍚庣殑浣欐枡
+  glassDetails.splice(0, glassDetails.length, ...nonGrayRects, ...merged);
 };
 
+// 纭繚杩斿洖鐨勫尯鍩熶笉閲嶅彔
+const calculateRemainingAreas = (totalWidth, totalHeight, obstacles) => {
+  // 浠庢暣涓師鐗囧紑濮�
+  let remaining = [{ x: 0, y: 0, width: totalWidth, height: totalHeight }];
+
+  // 閫愪釜澶勭悊闅滅鐗╋紙宸叉斁缃殑鐜荤拑鐗囷級
+  obstacles.forEach(obstacle => {
+    remaining = cutRemainingAreas(remaining, obstacle, totalWidth, totalHeight);
+  });
+
+  // 瀵圭粨鏋滆繘琛屾帓搴忥紝纭繚涓�鑷存��
+  remaining.sort((a, b) => {
+    if (a.x !== b.x) return a.x - b.x;
+    return a.y - b.y;
+  });
+
+  return remaining;
+};
+
+
+// 璋冩暣鍚庨噸鏂拌绠楃伆鑹蹭綑鏂�
 const adjustGrayRectangles = (layoutIndex) => {
   const layout = layouts.value[layoutIndex];
-  const rects = layout.rects;
-  const nonGrayRects = rects.filter(rect => !rect.isRemain);
+  const glassDetails = layout.glassDetails;
 
-  const remainingAreas = calculateRemainingAreas(layout.width, layout.height, nonGrayRects);
+  // 1. 绛涢�夊嚭闈炰綑鏂欑殑鐜荤拑鐗囷紙鍗冲疄闄呰鍒囧壊鐨勭幓鐠冪墖锛�
+  const nonGrayRects = glassDetails.filter(glassDetail => !glassDetail.isRemain);
 
-  const currentGrayRects = rects.filter(r => r.isRemain);
-  currentGrayRects.forEach((_, index) => {
-    if (index >= remainingAreas.length) {
-      rects.splice(index, 1);
-    }
+  // 2. 璁$畻鍓╀綑鍙敤鍖哄煙
+  let remainingAreas = calculateRemainingAreas(layout.width, layout.height, nonGrayRects);
+
+  // 3. 鍘婚噸澶勭悊 - 鏇翠弗鏍肩殑鍘婚噸閫昏緫
+  const uniqueArr = removeDuplicateAreas(remainingAreas);
+
+  // 4. 鑾峰彇褰撳墠宸插瓨鍦ㄧ殑浣欐枡鐭╁舰锛堥渶瑕佷繚鐣欏紩鐢ㄤ互渚挎洿鏂帮級
+  const currentGrayRects = glassDetails.filter(r => r.isRemain);
+
+  // 5. 娓呴櫎鎵�鏈夌幇鏈夌殑浣欐枡鐭╁舰
+  // 鍏堟敹闆嗛潪浣欐枡鐭╁舰
+  const nonRemainRects = glassDetails.filter(r => !r.isRemain);
+
+  // 6. 閲嶆柊鏋勫缓鐜荤拑璇︽儏鏁扮粍
+  // 淇濈暀闈炰綑鏂欑煩褰�
+  const newGlassDetails = [...nonRemainRects];
+
+  // 娣诲姞鏂扮殑浣欐枡鐭╁舰
+  uniqueArr.forEach((area) => {
+    newGlassDetails.push({
+      x: area.x,
+      y: area.y,
+      width: area.width,
+      height: area.height,
+      isRemain: true
+    });
   });
 
-  remainingAreas.forEach((area, index) => {
-    if (index < currentGrayRects.length) {
-      currentGrayRects[index].x = Math.round(area.x);
-      currentGrayRects[index].y = Math.round(area.y);
-      currentGrayRects[index].w = Math.round(area.w);
-      currentGrayRects[index].h = Math.round(area.h);
-    } else {
-      rects.push({
-        x: Math.round(area.x),
-        y: Math.round(area.y),
-        w: Math.round(area.w),
-        h: Math.round(area.h),
-        isRemain: true
-      });
-    }
-  });
+  // 7. 鏇存柊甯冨眬鐨勭幓鐠冭鎯�
+  layout.glassDetails = newGlassDetails;
 
-  mergeAdjacentGrayRects(rects);
+  // 8. 鍚堝苟鐩搁偦鐨勪綑鏂欑煩褰�
+  mergeAdjacentGrayRects(layout.glassDetails, layout.width, layout.height);
 };
 
+
+const removeDuplicateAreas = (areas) => {
+  const result = [];
+
+  areas.forEach(area => {
+    // 妫�鏌ユ槸鍚︿笌宸插瓨鍦ㄧ殑鍖哄煙閲嶅彔鎴栫浉绛�
+    const isDuplicate = result.some(existingArea => {
+      return (
+          existingArea.x === area.x &&
+          existingArea.y === area.y &&
+          existingArea.width === area.width &&
+          existingArea.height === area.height
+      );
+    });
+
+    if (!isDuplicate) {
+      result.push(area);
+    }
+  });
+
+  return result;
+};
+
+
+
+//鏃嬭浆鏂规硶
 const rotateRect = (layoutIndex, rectIndex) => {
   const layout = layouts.value[layoutIndex];
-  const rect = layout.rects[rectIndex];
-  const originalState = { ...rect };
+  const glassDetail = layout.glassDetails[rectIndex];
+  const originalState = { ...glassDetail };
 
-  // 鏃嬭浆鐭╁舰
-  const temp = rect.w;
-  rect.w = rect.h;
-  rect.h = temp;
+  const temp = glassDetail.width;
+  glassDetail.width = glassDetail.height;
+  glassDetail.height = temp;
 
-  // 妫�鏌ユ棆杞悗鏄惁涓庡叾浠栬摑鑹茬煩褰㈤噸鍙�
-  const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
+  const otherRects = layout.glassDetails.filter(r => !r.isRemain && r !== glassDetail);
   let isValidRotation = true;
 
   otherRects.forEach(otherRect => {
-    if (checkOverlap(rect, otherRect)) {
+    if (checkOverlap(glassDetail, otherRect)) {
       isValidRotation = false;
     }
   });
 
-  // 妫�鏌ユ槸鍚﹁秴鍑哄竷灞�杈圭晫
-  if (rect.x + rect.w > layout.width || rect.y + rect.h > layout.height) {
+  if (glassDetail.x + glassDetail.width > layout.width || glassDetail.y + glassDetail.height > layout.height) {
     isValidRotation = false;
   }
 
   if (isValidRotation) {
+    // 鏇存柊glassPoint鍧愭爣锛堝鏋滃瓨鍦級
+    if (glassDetail.glassPoint && Array.isArray(glassDetail.glassPoint)) {
+      // 淇濆瓨鍘熷鐐瑰潗鏍�
+      const originalPoints = JSON.parse(JSON.stringify(glassDetail.glassPoint));
+
+      // 鏃嬭浆鐐瑰潗鏍囷紙浠ョ煩褰㈠乏涓婅涓哄師鐐圭殑鏃嬭浆锛�
+      glassDetail.glassPoint.forEach((point, index) => {
+        // 璁$畻鐩稿浜庣煩褰㈠乏涓婅鐨勫潗鏍�
+        const relX = originalPoints[index].X - originalState.x;
+        const relY = originalPoints[index].Y - originalState.y;
+
+        // 鏃嬭浆90搴﹀悗鐨勫潗鏍囷紙椤烘椂閽堬級
+        point.X = originalState.x + relY;
+        point.Y = originalState.y + (originalState.width - relX);
+        // 娣诲姞绮惧害鎺у埗
+        point.X = parseFloat(point.X.toFixed(2));
+        point.Y = parseFloat(point.Y.toFixed(2));
+      });
+    }
     adjustGrayRectangles(layoutIndex);
   } else {
-    // 鎭㈠鍘熺姸
-    rect.w = originalState.w;
-    rect.h = originalState.h;
+    glassDetail.width = originalState.width;
+    glassDetail.height = originalState.height;
     ElMessage.warning('鏃犳硶鏃嬭浆锛屽瓨鍦ㄩ噸鍙犳垨瓒呭嚭杈圭晫');
   }
 };
 
+//绉诲姩鏃嬭浆鏂规硶
 const moveRectAndRotate = (layoutIndex, rectIndex, direction) => {
   const layout = layouts.value[layoutIndex];
-  const rect = layout.rects[rectIndex];
-  const grayRects = layout.rects.filter(r => r.isRemain);
+  const glassDetail = layout.glassDetails[rectIndex];
+  const grayRects = layout.glassDetails.filter(r => r.isRemain);
 
-  // 鏃嬭浆鐭╁舰
-  const temp = rect.w;
-  rect.w = rect.h;
-  rect.h = temp;
+  const temp = glassDetail.width;
+  glassDetail.width = glassDetail.height;
+  glassDetail.height = temp;
 
-  // 妫�鏌ユ棆杞悗鐨勭煩褰㈡槸鍚﹀彲浠ユ斁缃湪鏌愪釜鐏拌壊鐭╁舰鐨勪綅缃�
   const canPlace = grayRects.some(grayRect => {
-    return grayRect.w >= rect.w && grayRect.h >= rect.h;
+    return grayRect.width >= glassDetail.width && grayRect.height >= glassDetail.height;
   });
 
   if (!canPlace) {
-    // 濡傛灉涓嶈兘鏀剧疆锛屾仮澶嶅師鐘�
-    const temp = rect.w;
-    rect.w = rect.h;
-    rect.h = temp;
+    const temp = glassDetail.width;
+    glassDetail.width = glassDetail.height;
+    glassDetail.height = temp;
     ElMessage.warning('鏃犳硶鏃嬭浆锛屾病鏈夎冻澶熺殑绌洪棿');
     return;
   }
 
-  // 璋冩暣鐏拌壊鐭╁舰
   adjustGrayRectangles(layoutIndex);
-
-  // 绉诲姩鐭╁舰
   moveRect(layoutIndex, rectIndex, direction);
 };
 
+//绉诲姩鏂规硶
 const moveRect = (layoutIndex, rectIndex, direction) => {
   const layout = layouts.value[layoutIndex];
-  const rect = layout.rects[rectIndex];
-  const originalState = { ...rect };
+  const glassDetail = layout.glassDetails[rectIndex];
+  const originalState = { ...glassDetail };
 
-  // 璁$畻鍓╀綑绌洪棿
-  const remainingAreas = calculateRemainingAreas(layout.width, layout.height, layout.rects.filter(r => !r.isRemain));
-  
-  // 鏍规嵁鏂瑰悜璁$畻鍙Щ鍔ㄧ殑鏈�澶ф闀�
   let maxStep = 0;
+  const obstacles = layout.glassDetails.filter(r => r.isRemain || r !== glassDetail);
+
   switch (direction) {
     case 'up':
-      maxStep = rect.y;
+      maxStep = getAvailableSpaceUp(glassDetail, layout, obstacles);
       break;
     case 'down':
-      maxStep = layout.height - (rect.y + rect.h);
+      maxStep = getAvailableSpaceDown(glassDetail, layout, obstacles);
       break;
     case 'left':
-      maxStep = rect.x;
+      maxStep = getAvailableSpaceLeft(glassDetail, layout, obstacles);
       break;
     case 'right':
-      maxStep = layout.width - (rect.x + rect.w);
+      maxStep = getAvailableSpaceRight(glassDetail, layout, obstacles);
       break;
   }
 
-  // 绉诲姩姝ラ暱锛屾牴鎹墿浣欑┖闂村姩鎬佽皟鏁�
-  const stepSize = maxStep;
-  const actualStep = Math.min(maxStep, stepSize);
+  if (maxStep <= 0) {
+    ElMessage.warning('鏃犳硶绉诲姩锛屾病鏈夎冻澶熺殑绌洪棿');
+    return;
+  }
 
-  // 绉诲姩鐭╁舰
+
+  // 淇濆瓨鍘熷鍧愭爣
+  const originalX = glassDetail.x;
+  const originalY = glassDetail.y;
+
   switch (direction) {
     case 'up':
-      rect.y -= actualStep;
+      glassDetail.y += maxStep;
       break;
     case 'down':
-      rect.y += actualStep;
+      glassDetail.y -= maxStep;
       break;
     case 'left':
-      rect.x -= actualStep;
+      glassDetail.x -= maxStep;
       break;
     case 'right':
-      rect.x +=actualStep;
+      glassDetail.x += maxStep;
       break;
   }
 
-  // 妫�鏌ユ槸鍚︿笌鍏朵粬钃濊壊鐭╁舰閲嶅彔
-  const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
+  const otherRects = layout.glassDetails.filter(r => !r.isRemain && r !== glassDetail);
   let isValidMove = true;
 
   otherRects.forEach(otherRect => {
-    if (checkOverlap(rect, otherRect)) {
+    if (checkOverlap(glassDetail, otherRect)) {
       isValidMove = false;
     }
   });
 
-  // 妫�鏌ユ槸鍚﹁秴鍑哄竷灞�杈圭晫
-  if (rect.x < 0 || rect.y < 0 ||
-      rect.x + rect.w > layout.width ||
-      rect.y + rect.h > layout.height) {
+  if (glassDetail.x < 0 || glassDetail.y < 0 ||
+      glassDetail.x + glassDetail.width > layout.width ||
+      glassDetail.y + glassDetail.height > layout.height) {
     isValidMove = false;
   }
 
   if (isValidMove) {
+    // 鏇存柊glassPoint鍧愭爣
+    if (glassDetail.glassPoint && Array.isArray(glassDetail.glassPoint)) {
+      const offsetX = glassDetail.x - originalX;
+      const offsetY = glassDetail.y - originalY;
+
+      glassDetail.glassPoint.forEach(point => {
+        point.X += offsetX;
+        point.Y += offsetY;
+        // 娣诲姞绮惧害鎺у埗
+        point.X = parseFloat(point.X.toFixed(2));
+        point.Y = parseFloat(point.Y.toFixed(2));
+      });
+    }
     adjustGrayRectangles(layoutIndex);
   } else {
-    // 鎭㈠鍘熺姸
-    rect.x = originalState.x;
-    rect.y = originalState.y;
+    glassDetail.x = originalState.x;
+    glassDetail.y = originalState.y;
     ElMessage.warning('鏃犳硶绉诲姩锛屽瓨鍦ㄩ噸鍙犳垨瓒呭嚭杈圭晫');
   }
 };
 
+//鍒犻櫎灏忕墖
 const deleteRect = (layoutIndex, rectIndex) => {
   const layout = layouts.value[layoutIndex];
-  layout.rects.splice(rectIndex, 1);
+  layout.glassDetails.splice(rectIndex, 1);
   adjustGrayRectangles(layoutIndex);
 };
 
+//鍒ゆ柇鍘熺墖璺熷皬鐗囩Щ鍔ㄦ槸鍚﹁秴鍑�
 const checkOverlap = (rect1, rect2) => {
-  return !(rect1.x + rect1.w <= rect2.x ||
-           rect1.x >= rect2.x + rect2.w ||
-           rect1.y + rect1.h <= rect2.y ||
-           rect1.y >= rect2.y + rect2.h);
+  return !(rect1.x + rect1.width <= rect2.x ||
+           rect1.x >= rect2.x + rect2.width ||
+           rect1.y + rect1.height <= rect2.y ||
+           rect1.y >= rect2.y + rect2.height);
 };
 
-const calculateRemainingAreas = (totalWidth, totalHeight, obstacles) => {
-  let remaining = [{ x: 0, y: 0, w: totalWidth, h: totalHeight }];
-  obstacles.forEach(rect => {
-    remaining = cutRemainingAreas(remaining, rect);
-  });
-  return remaining;
-};
+//閲嶆柊璁$畻浣欐枡鍧愭爣浠ュ強灏哄1
+// const calculateRemainingAreas = (totalWidth, totalHeight, obstacles) => {
+//   let remaining = [{ x: 0, y: 0, width: totalWidth, height: totalHeight }];
+//   obstacles.forEach(glassDetail => {
+//     remaining = cutRemainingAreas(remaining, glassDetail,totalWidth,totalHeight);
+//   });
+//   return remaining;
+// };
 
-const cutRemainingAreas = (remainingAreas, obstacle) => {
+//閲嶆柊璁$畻浣欐枡鍧愭爣浠ュ強灏哄2
+const cutRemainingAreas = (remainingAreas, obstacle, totalWidth, totalHeight) => {
   const newRemaining = [];
+
   remainingAreas.forEach(area => {
-    if (checkOverlap(area, obstacle)) {
-      if (obstacle.x > area.x) {
-        newRemaining.push({
-          x: area.x,
-          y: area.y,
-          w: obstacle.x - area.x,
-          h: area.h
-        });
-      }
-      if (obstacle.x + obstacle.w < area.x + area.w) {
-        newRemaining.push({
-          x: obstacle.x + obstacle.w,
-          y: area.y,
-          w: area.w - (obstacle.x + obstacle.w - area.x),
-          h: area.h
-        });
-      }
-      if (obstacle.y > area.y) {
-        newRemaining.push({
-          x: area.x,
-          y: area.y,
-          w: area.w,
-          h: obstacle.y - area.y
-        });
-      }
-      if (obstacle.y + obstacle.h < area.y + area.h) {
-        newRemaining.push({
-          x: area.x,
-          y: obstacle.y + obstacle.h,
-          w: area.w,
-          h: area.h - (obstacle.y + obstacle.h - area.y)
-        });
-      }
-    } else {
+    // 濡傛灉闅滅鐗╀笌褰撳墠鍖哄煙娌℃湁閲嶅彔锛屼繚鐣欏師鍖哄煙
+    if (!checkOverlap(area, obstacle)) {
       newRemaining.push(area);
+      return;
+    }
+
+    // 璁$畻閲嶅彔鍖哄煙鐨勮竟鐣�
+    const overlapLeft = Math.max(area.x, obstacle.x);
+    const overlapRight = Math.min(area.x + area.width, obstacle.x + obstacle.width);
+    const overlapTop = Math.max(area.y, obstacle.y);
+    const overlapBottom = Math.min(area.y + area.height, obstacle.y + obstacle.height);
+
+    // 鐢熸垚鍥涗釜鍙兘鐨勬柊鍖哄煙锛堜笂銆佷笅銆佸乏銆佸彸锛�
+
+    // 涓婃柟鍖哄煙
+    if (overlapTop > area.y) {
+      newRemaining.push({
+        x: area.x,
+        y: area.y,
+        width: area.width,
+        height: overlapTop - area.y
+      });
+    }
+
+    // 涓嬫柟鍖哄煙
+    if (overlapBottom < area.y + area.height) {
+      newRemaining.push({
+        x: area.x,
+        y: overlapBottom,
+        width: area.width,
+        height: area.y + area.height - overlapBottom
+      });
+    }
+
+    // 宸︽柟鍖哄煙锛堜粎鍦ㄩ噸鍙犲尯鍩熺殑鍨傜洿鑼冨洿鍐咃級
+    if (overlapLeft > area.x) {
+      const regionTop = overlapTop;
+      const regionBottom = overlapBottom;
+      newRemaining.push({
+        x: area.x,
+        y: regionTop,
+        width: overlapLeft - area.x,
+        height: regionBottom - regionTop
+      });
+    }
+
+    // 鍙虫柟鍖哄煙锛堜粎鍦ㄩ噸鍙犲尯鍩熺殑鍨傜洿鑼冨洿鍐咃級
+    if (overlapRight < area.x + area.width) {
+      const regionTop = overlapTop;
+      const regionBottom = overlapBottom;
+      newRemaining.push({
+        x: overlapRight,
+        y: regionTop,
+        width: area.x + area.width - overlapRight,
+        height: regionBottom - regionTop
+      });
     }
   });
+
   return newRemaining;
 };
 
+//瀹氫箟姣忎釜鐗堝浘鐨勭患鍚堝唴瀹�
 const getCurrentRectInfo = (layoutIndex) => {
   const layout = layouts.value[layoutIndex];
-  const rect = layout.rects[focusIndex.value?.rectIndex || 0];
-  if (!rect) return '';
+/*  const glassDetail = layout.glassDetails[focusIndex.value?.rectIndex || 0];
+  if (!glassDetail) return '';*/
   const totalRects = layouts.value.length;
   const currentRectIndex = layoutIndex + 1;
-  const width = layout.width;
-  const height = layout.height;
-  const percentage = ((rect.w / layout.width) * 100).toFixed(1) + '%';
+  const width = layout.realWidth;
+  const height = layout.realHeight;
+  const percentage = (layout.usageRate * 100).toFixed(2) + '%';
   return `${currentRectIndex}/${totalRects} ${width}脳${height} 脳1 ${percentage}`;
 };
 
+//鐐瑰嚮宸﹁竟鐗堝浘鍒囨崲
 const selectLayout = (layoutIndex) => {
   selectedLayoutIndex.value = layoutIndex;
 };
 
+//鎶婁紶杈撶殑鏁版嵁璧嬪��
 const updateLayout = () => {
   if (!layoutPanel.value) return;
-  layouts.value = props.layoutData.Layouts;
+  layoutsHead.value = props.layoutData;
+  layouts.value = props.layoutData.layouts;
 };
 
+//鍚戜笂绉诲姩璁$畻鍧愭爣
+const getAvailableSpaceUp = (glassDetail, layout, obstacles) => {
+  let maxSpace = layout.height - glassDetail.y - glassDetail.height;
+  obstacles.forEach(obstacle => {
+    if (obstacle.y > glassDetail.y + glassDetail.height &&
+        obstacle.x <= glassDetail.x + glassDetail.width &&
+        obstacle.x + obstacle.width >= glassDetail.x) {
+      maxSpace = Math.min(maxSpace, obstacle.y - (glassDetail.y + glassDetail.height));
+    }
+  });
+  return maxSpace;
+};
 
-let clickEventListener = null;
+//鍚戜笅绉诲姩璁$畻鍧愭爣
+const getAvailableSpaceDown = (glassDetail, layout, obstacles) => {
+  let maxSpace = glassDetail.y;
+  obstacles.forEach(obstacle => {
+    if (obstacle.y + obstacle.height < glassDetail.y &&
+        obstacle.x <= glassDetail.x + glassDetail.width &&
+        obstacle.x + obstacle.width >= glassDetail.x) {
+      maxSpace = Math.min(maxSpace, glassDetail.y - (obstacle.y + obstacle.height));
+    }
+  });
+  return maxSpace;
+};
+
+//鍚戝乏绉诲姩璁$畻鍧愭爣
+const getAvailableSpaceLeft = (glassDetail, layout, obstacles) => {
+  let maxSpace = glassDetail.x;
+  obstacles.forEach(obstacle => {
+    if (obstacle.x + obstacle.width < glassDetail.x &&
+        obstacle.y <= glassDetail.y + glassDetail.height &&
+        obstacle.y + obstacle.height >= glassDetail.y) {
+      maxSpace = Math.min(maxSpace, glassDetail.x - (obstacle.x + obstacle.width));
+    }
+  });
+  return maxSpace;
+};
+
+//鍚戝彸绉诲姩璁$畻鍧愭爣
+const getAvailableSpaceRight = (glassDetail, layout, obstacles) => {
+  let maxSpace = layout.width - (glassDetail.x + glassDetail.width);
+  obstacles.forEach(obstacle => {
+    if (obstacle.x > glassDetail.x + glassDetail.width &&
+        obstacle.y <= glassDetail.y + glassDetail.height &&
+        obstacle.y + obstacle.height >= glassDetail.y) {
+      maxSpace = Math.min(maxSpace, obstacle.x - (glassDetail.x + glassDetail.width));
+    }
+  });
+  return maxSpace;
+};
+
+let moveInterval = null;
+
+//鎸変笅鎸夐敭涓婁笅宸﹀彸
+const handleKeyDown = (event) => {
+  if (!focusIndex.value) return;
+
+  const { layoutIndex, rectIndex } = focusIndex.value;
+  const layout = layouts.value[layoutIndex];
+  const glassDetail = layout.glassDetails[rectIndex];
+  const obstacles = layout.glassDetails.filter(r => r.isRemain || r !== glassDetail);
+
+  switch (event.key) {
+    case 'ArrowUp':
+      event.preventDefault();
+      if (!moveInterval) {
+        moveInterval = setInterval(() => {
+          moveRect(layoutIndex, rectIndex, 'down');
+        }, 50);
+      }
+      break;
+    case 'ArrowDown':
+      event.preventDefault();
+      if (!moveInterval) {
+        moveInterval = setInterval(() => {
+          moveRect(layoutIndex, rectIndex, 'up');
+        }, 50);
+      }
+      break;
+    case 'ArrowLeft':
+      event.preventDefault();
+      if (!moveInterval) {
+        moveInterval = setInterval(() => {
+          moveRect(layoutIndex, rectIndex, 'left');
+        }, 50);
+      }
+      break;
+    case 'ArrowRight':
+      event.preventDefault();
+      if (!moveInterval) {
+        moveInterval = setInterval(() => {
+          moveRect(layoutIndex, rectIndex, 'right');
+        }, 50);
+      }
+      break;
+  }
+};
+
+//鏉惧紑鎸夐敭涓婁笅宸﹀彸
+const handleKeyUp = (event) => {
+  if (event.key === 'ArrowUp' || event.key === 'ArrowDown' ||
+      event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
+    if (moveInterval) {
+      clearInterval(moveInterval);
+      moveInterval = null;
+    }
+  }
+};
+
+//x闀滃儚
+const mirrorLayoutX = (layoutIndex) => {
+  const layout = layouts.value[layoutIndex];
+  const width = layout.width;
+  const glassDetails = [...layout.glassDetails]; // 鍒涘缓鍓湰閬垮厤鐩存帴淇敼
+
+  glassDetails.forEach(glassDetail => {
+    // 璁$畻X闀滃儚鍚庣殑鍧愭爣
+    const newX = width - glassDetail.x - glassDetail.width;
+    const newY = glassDetail.y;
+
+    // 鏇存柊鐭╁舰浣嶇疆
+    glassDetail.x = newX;
+    glassDetail.y = newY;
+
+    // 鏇存柊glassPoint鍧愭爣
+    if (glassDetail.glassPoint && Array.isArray(glassDetail.glassPoint)) {
+      glassDetail.glassPoint.forEach(point => {
+        point.X = width - point.X;
+        point.X = parseFloat(point.X.toFixed(2));
+        point.Y = parseFloat(point.Y.toFixed(2));
+      });
+    }
+  });
+
+  // 鏇存柊甯冨眬
+  layout.glassDetails = glassDetails;
+  adjustGrayRectangles(layoutIndex);
+};
+
+//y闀滃儚
+const mirrorLayoutY = (layoutIndex) => {
+  const layout = layouts.value[layoutIndex];
+  const height = layout.height;
+  const glassDetails = [...layout.glassDetails]; // 鍒涘缓鍓湰閬垮厤鐩存帴淇敼
+
+  glassDetails.forEach(glassDetail => {
+    // 璁$畻Y闀滃儚鍚庣殑鍧愭爣
+    const newX = glassDetail.x;
+    const newY = height - glassDetail.y - glassDetail.height;
+
+    // 鏇存柊鐭╁舰浣嶇疆
+    glassDetail.y = newY;
+
+    // 鏇存柊glassPoint鍧愭爣
+    if (glassDetail.glassPoint && Array.isArray(glassDetail.glassPoint)) {
+      glassDetail.glassPoint.forEach(point => {
+        point.Y = height - point.Y;
+        // 娣诲姞绮惧害鎺у埗
+        point.X = parseFloat(point.X.toFixed(2));
+        point.Y = parseFloat(point.Y.toFixed(2));
+      });
+    }
+  });
+
+  // 鏇存柊甯冨眬
+  layout.glassDetails = glassDetails;
+  adjustGrayRectangles(layoutIndex);
+};
+
 onMounted(() => {
   fetchSettings(username);
-  setTimeout(updateLayout, 500);
+  updateLayout();
 
   selectedLayoutIndex.value = 0;
 
-   // 娣诲姞鍏ㄥ眬鐐瑰嚮浜嬩欢鐩戝惉鍣�
-   clickEventListener = (event) => {
-    // 妫�鏌ユ槸鍚﹀瓨鍦ㄥ彸閿彍鍗�
+  clickEventListener = (event) => {
     const contextMenus = document.querySelectorAll('.context-menu');
     if (contextMenus.length > 0) {
-      // 绉婚櫎鎵�鏈夊彸閿彍鍗�
       contextMenus.forEach(menu => menu.remove());
     }
   };
   document.addEventListener('click', clickEventListener);
 
+  document.addEventListener('keydown', handleKeyDown);
+  document.addEventListener('keyup', handleKeyUp);
 });
 
 onUnmounted(() => {
   rectsElements.value = {};
-   // 绉婚櫎鍏ㄥ眬鐐瑰嚮浜嬩欢鐩戝惉鍣�
-   if (clickEventListener) {
+  if (clickEventListener) {
     document.removeEventListener('click', clickEventListener);
+    clickEventListener = null;
   }
+  document.removeEventListener('keydown', handleKeyDown);
+  document.removeEventListener('keyup', handleKeyUp);
 });
 </script>
 
@@ -865,7 +1428,7 @@
   margin-top: 50px;
 }
 
-.layout-rect {
+.layout-glassDetail {
   user-select: none;
 }
 
@@ -884,26 +1447,29 @@
   font-weight: bold;
 }
 
-.rect-content {
-  display: grid;
-  grid-template-columns: 1fr;
-  grid-template-rows: 1fr;
+.glassDetail-content {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
   padding: 5px;
+  min-width: 60px;
+  min-height: 20px;
+  white-space: normal;
+  overflow-wrap: break-word;
 }
 
 .size {
-  grid-row: 1;
-  grid-column: 1;
-  color: #444;
   font-size: 12px;
+  color: #444;
+  white-space: normal;
+  word-wrap: break-word;
 }
 
-.jia-hao .liuchengka {
-  grid-row: 2;
-  grid-column: 1;
-  margin: auto;
+.jia-hao, .liuchengka {
   font-size: 14px;
   font-weight: bold;
+  white-space: normal;
+  word-wrap: break-word;
 }
 
 .sidebar-item {
@@ -931,4 +1497,17 @@
 .context-menu div:hover {
   background-color: #f0f0f0;
 }
+
+.folder-header {
+  font-weight: bold;
+}
+
+.folder-header:hover {
+  background-color: #d0d0d0 !important;
+}
+
+.folder-content {
+  border-left: 2px solid #ccc;
+  margin-left: 5px;
+}
 </style>

--
Gitblit v1.8.0