chenlu
2025-11-21 d473c7b2b07cfeee3740f40dfdc95d722d8da3c2
north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/OptimizationRect.vue
@@ -1,15 +1,15 @@
<template>
  <div style="display: flex; height: 90vh;">
    <!-- Sidebar -->
    <div class="sidebar" style="width: 200px; background: #f4f4f4; padding: 10px;">
    <div class="sidebar" style="width: 200px; background: #f4f4f4; padding: 10px; height: 93%; overflow-y: auto; max-height: 90vh; border-radius: 8px;">
      <div
        v-for="(layout, layoutIndex) in layouts"
        :key="layoutIndex"
        class="sidebar-item"
        @click="selectLayout(layoutIndex)"
        :class="{ 'selected': selectedLayoutIndex === layoutIndex }"
          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  }}
        {{ layout.realWidth }} × {{ layout.realHeight }} × {{ layout.quantity }}
      </div>
    </div>
@@ -71,8 +71,7 @@
      </div>
    </div>
    <!-- 提交按钮 -->
    <button @click="submitLayouts" style="position: fixed; top: 90px; 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>
@@ -80,9 +79,9 @@
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue';
import { useRouter } from 'vue-router'; // 添加这行
import { useRouter } from 'vue-router';
import request from "@/utils/request";
const router = useRouter(); // 添加这行
const router = useRouter();
import { useI18n } from "vue-i18n";
import { ElMessage, ElMessageBox } from "element-plus";
import useUserInfoStore from "@/stores/userInfo";
@@ -120,10 +119,10 @@
const submitLayouts = async () => {
  layouts.value.forEach(layout => {
    layout.glassDetails.forEach(glassDetail => {
      glassDetail.x = Math.round(glassDetail.x);
      glassDetail.y = Math.round(glassDetail.y);
      glassDetail.width = Math.round(glassDetail.width);
      glassDetail.height = Math.round(glassDetail.height);
      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');
@@ -553,6 +552,11 @@
  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
@@ -583,6 +587,21 @@
  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
@@ -603,8 +622,8 @@
      (props.gh - 100) / layout.height
    );
    glassDetail.x = Math.round(glassDetail.x);
    glassDetail.y = Math.round(glassDetail.y);
    glassDetail.x = parseFloat(glassDetail.x.toFixed(2));
    glassDetail.y = parseFloat(glassDetail.y.toFixed(2));
    adjustAlignmentPosition(layoutIndex, rectIndex);
  }
@@ -652,17 +671,15 @@
  const grayRects = glassDetails.filter(r => r.isRemain);
  const nonGrayRects = glassDetails.filter(r => !r.isRemain);
  // 按坐标排序,优先按x坐标,其次按y坐标
  // 按坐标排序,优先按y坐标,其次按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;
  const merged = [];
  // 从第一个矩形开始
  let current = { ...grayRects[0] };
  // 遍历所有余料矩形进行合并
@@ -686,15 +703,25 @@
    else {
      // 无法合并,保存当前矩形,开始新的合并
      merged.push({
        x: Math.round(current.x),
        y: Math.round(current.y),
        width: Math.round(current.width),
        height: Math.round(current.height),
        x: current.x,
        y: current.y,
        width: current.width,
        height: current.height,
        isRemain: true
      });
      current = { ...next };
    }
  }
  // 添加最后一个矩形
  merged.push({
    x: current.x,
    y: current.y,
    width: current.width,
    height: current.height,
    isRemain: true
  });
  // 重新构建数组:非余料 + 合并后的余料
  glassDetails.splice(0, glassDetails.length, ...nonGrayRects, ...merged);
};
@@ -747,10 +774,10 @@
  // 添加新的余料矩形
  uniqueArr.forEach((area) => {
    newGlassDetails.push({
      x: Math.round(area.x),
      y: Math.round(area.y),
      width: Math.round(area.width),
      height: Math.round(area.height),
      x: area.x,
      y: area.y,
      width: area.width,
      height: area.height,
      isRemain: true
    });
  });
@@ -811,6 +838,25 @@
  }
  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 {
    glassDetail.width = originalState.width;
@@ -874,6 +920,11 @@
    return;
  }
  // 保存原始坐标
  const originalX = glassDetail.x;
  const originalY = glassDetail.y;
  switch (direction) {
    case 'up':
      glassDetail.y += maxStep;
@@ -905,6 +956,19 @@
  }
  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 {
    glassDetail.x = originalState.x;
@@ -942,60 +1006,62 @@
  const newRemaining = [];
  remainingAreas.forEach(area => {
    // 如果障碍物与当前区域有重叠
    if (checkOverlap(area, obstacle)) {
      // 切分当前区域为最多4个新区域
      // 左侧区域
      if (obstacle.x > area.x) {
        newRemaining.push({
          x: area.x,
          y: area.y,
          width: obstacle.x - area.x,
          height: area.height
        });
      }
      // 右侧区域
      if (obstacle.x + obstacle.width < area.x + area.width) {
        newRemaining.push({
          x: obstacle.x + obstacle.width,
          y: area.y,
          width: area.x + area.width - (obstacle.x + obstacle.width),
          height: area.height
        });
      }
      // 上方区域(仅在障碍物左右边界之间的区域)
      if (obstacle.y > area.y) {
        const startX = Math.max(area.x, obstacle.x);
        const endX = Math.min(area.x + area.width, obstacle.x + obstacle.width);
        if (endX > startX) {
          newRemaining.push({
            x: startX,
            y: area.y,
            width: endX - startX,
            height: obstacle.y - area.y
          });
        }
      }
      // 下方区域(仅在障碍物左右边界之间的区域)
      if (obstacle.y + obstacle.height < area.y + area.height) {
        const startX = Math.max(area.x, obstacle.x);
        const endX = Math.min(area.x + area.width, obstacle.x + obstacle.width);
        if (endX > startX) {
          newRemaining.push({
            x: startX,
            y: obstacle.y + obstacle.height,
            width: endX - startX,
            height: area.y + area.height - (obstacle.y + obstacle.height)
          });
        }
      }
    } 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
      });
    }
  });
@@ -1151,6 +1217,15 @@
    // 更新矩形位置
    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));
      });
    }
  });
  // 更新布局
@@ -1171,6 +1246,16 @@
    // 更新矩形位置
    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));
      });
    }
  });
  // 更新布局