wuyouming666
2025-04-07 2761fdf62f9f6c0dd931812589643adbe40efb83
north-glass-erp/northglass-erp/src/views/pp/glassOptimize/page/RectRenderer.vue
@@ -1,21 +1,26 @@
<template>
  <div ref="layoutPanel" :class="panelClass" :style="panelStyle">
    <div v-for="(layout, layoutIndex) in layouts" :key="layoutIndex" class="layout-wrapper">
      <!-- 布局信息标签 -->
      <div class="layout-info" :style="layoutInfoStyle(layoutIndex)">
         {{ getCurrentRectInfo(layoutIndex) }}
      </div>
      <!-- 布局容器 -->
      <div class="layout-container" :style="layoutContainerStyle(layoutIndex)">
        <div v-for="(rect, rectIndex) in layout.rects" :key="rectIndex"
             :ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
             :class="rectClass"
             :style="rectStyle(rect, layoutIndex)"
             @click="handleRectClick(layoutIndex, rectIndex)">
          <div v-if="!rect.isRemain" class="rect-content">
            <div class="size">{{ rect.w }}×{{ rect.h }}</div>
            <div class="jia-hao">{{ rect.JiaHao }}</div>
    <div id="printFlowCard">
      <div v-for="(layout, layoutIndex) in layouts" :key="layoutIndex" class="layout-wrapper">
        <div class="header" :style="headerStyle(layoutIndex)">
          工程号{{ processId }}
          {{ getCurrentRectInfo(layoutIndex) }}
        </div>
        <div class="layout-container" :style="layoutContainerStyle(layoutIndex)">
          <div class="grid-container" :class="`cols-${printColumns}`">
            <div
              v-for="(rect, rectIndex) in layout.rects"
              :key="rectIndex"
              :ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
              :class="rectClass"
              :style="rectStyle(rect, layoutIndex)"
              @click="handleRectClick(layoutIndex, rectIndex)"
            >
              <div v-if="!rect.isRemain" class="rect-content">
                <div class="size">{{ rect.w }}×{{ rect.h }}</div>
                <div class="jia-hao">{{ rect.JiaHao }}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
@@ -24,13 +29,16 @@
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue';
import { ref, reactive, onMounted, onUnmounted, watch, nextTick } from 'vue';
import request from "@/utils/request";
const props = defineProps({
  layoutData: { type: Object, required: true },
  gw: { type: Number, default: 1000 },
  gh: { type: Number, default: 1000 },
  style: { type: String, default: 'width:1000px;height:600px;display:block;background:gray' }
  gw: { type: Number, default: 1400 },
  gh: { type: Number, default: 1100 },
  style: { type: String, default: 'width:100%;height:800px;display:block;background:gray' },
  printLayout: { type: String, default: '2rows-2cols' }, // 可选值:4rows-2cols, 3rows-2cols, 3rows-1col, 2rows-2cols
  fixedPageHeight: { type: Number, default: 1100 } // 固定页面高度
});
const emit = defineEmits(['rectClicked']);
@@ -41,12 +49,29 @@
const panelClass = ref('');
const panelStyle = ref(props.style);
const rectClass = ref('layout-rect');
const processId = localStorage.getItem('projectNo');
const printColumns = ref(2); // 初始化为2列
const layoutsPerPage = ref(4); // 默认每页显示4个布局(2行×2列)
// 定义不同布局的放大比例
const layoutScales = {
  '4rows-2cols': 0.8, // 四行两列,较小的放大比例
  '3rows-2cols': 0.9, // 三行两列,适中的放大比例
  '3rows-1col': 1.0,  // 三行一列,较大的放大比例
  '2rows-2cols': 1   // 两行两列,较大的放大比例
};
// 监听printLayout变化
watch(() => props.printLayout, (newVal) => {
  adjustPrintLayout();
  updateLayout();
});
const layoutContainerStyle = (layoutIndex) => {
  const containerWidth = (props.gw - 210) / 2;
  const containerHeight = (props.gh - 100) / 3;
  const x = (layoutIndex % 2) * (containerWidth + 50);
  const y = Math.floor(layoutIndex / 2) * (containerHeight + 50);
  const containerWidth = (props.gw - 20) / printColumns.value; // 减少边距
  const containerHeight = (props.gh - 20) / Math.ceil(layoutsPerPage.value / printColumns.value);
  const x = (layoutIndex % printColumns.value) * containerWidth;
  const y = Math.floor(layoutIndex / printColumns.value) * containerHeight;
  return {
    position: 'absolute',
    left: `${x}px`,
@@ -54,34 +79,45 @@
    width: `${containerWidth}px`,
    height: `${containerHeight}px`,
    overflow: 'visible',
    border: '1px solid #ccc',
    background: '#fff'
    padding: '10px' // 添加内边距
  };
};
const layoutInfoStyle = (layoutIndex) => {
  const containerWidth = (props.gw - 210) / 2;
  const containerHeight = (props.gh - 100) / 3;
  const x = (layoutIndex % 2) * (containerWidth + 50);
  const y = Math.floor(layoutIndex / 2) * (containerHeight + 50);
const headerStyle = (layoutIndex) => {
  const containerWidth = (props.gw - 20) / printColumns.value;
  const containerHeight = (props.gh - 20) / Math.ceil(layoutsPerPage.value / printColumns.value);
  const x = (layoutIndex % printColumns.value) * containerWidth;
  const y = Math.floor(layoutIndex / printColumns.value) * containerHeight;
  const scale = Math.min(
    containerWidth,
    containerHeight
  ) * 1.2; // 放大1.2倍
  return {
    position: 'absolute',
    left: `${x}px`,
    top: `${y - 45}px`,
    background: 'none',
    width: `${scale}px`,
    textAlign: 'center',
    zIndex: 1000
    zIndex: 1000,
    background: '#ffffff',
    padding: '5px',
    fontSize: '12px'
  };
};
const rectStyle = (rect, layoutIndex) => {
  const layout = layouts.value[layoutIndex];
  const containerWidth = (props.gw - 100) / 2;
  const containerHeight = (props.gh - 100) / 3;
  const containerWidth = (props.gw - 100) / printColumns.value;
  const containerHeight = (props.gh - 100) / Math.ceil(layoutsPerPage.value / printColumns.value);
  // 根据当前打印布局获取放大比例
  const currentScale = layoutScales[props.printLayout] || 1.0;
  const scale = Math.min(
    containerWidth / layout.width,
    containerHeight / layout.height
  );
  ) * currentScale; // 应用当前布局的放大比例
  return {
    position: 'absolute',
    left: `${rect.x * scale}px`,
@@ -104,48 +140,181 @@
  const rect = layout.rects[focusIndex.value?.rectIndex || 0];
  if (!rect) return '';
  const totalRects = layouts.value.length;
  const currentRectIndex = layoutIndex+1;
  const currentRectIndex = layoutIndex + 1;
  const width = layout.width;
  const height = layout.height;
  const percentage = ((rect.w / layout.width) * 100).toFixed(1) + '%';
  return `${currentRectIndex}/${totalRects} ${width}×${height} ×1 ${percentage}`;
  const sum = layout.rects.reduce((sum, r) => sum + (r.w * r.h), 0);
  const areaUtilization = ((sum / (width * height)) * 100).toFixed(2);
  return `${currentRectIndex}/${totalRects} ${height}X${width}X1 ${areaUtilization}%`;
};
const adjustPrintLayout = () => {
  switch (props.printLayout) {
    case '4rows-2cols':
      printColumns.value = 2;
      layoutsPerPage.value = 8; // 4行×2列
      break;
    case '3rows-2cols':
      printColumns.value = 2;
      layoutsPerPage.value = 6; // 3行×2列
      break;
    case '3rows-1col':
      printColumns.value = 1;
      layoutsPerPage.value = 3; // 3行×1列
      break;
    case '2rows-2cols':
      printColumns.value = 2;
      layoutsPerPage.value = 4; // 2行×2列
      break;
    default:
      printColumns.value = 2;
      layoutsPerPage.value = 4;
  }
};
const updateLayout = () => {
  if (!layoutPanel.value) return;
  layouts.value = props.layoutData.Layouts;
  adjustPrintLayout();
  // 强制重新渲染
  layoutPanel.value.offsetHeight; // 触发布局更新
};
onMounted(() => {
   setTimeout(updateLayout, 500);
updateLayout();
});
onUnmounted(() => {
  rectsElements.value = {};
});
const print = () => {
  const el = document.getElementById('printFlowCard');
  const doc = document;
  const body = doc.body || doc.getElementsByTagName("body")[0];
  const printId = "print-" + Date.now();
  // 创建一个克隆的节点
  const content = document.createElement("div");
  content.id = printId;
  content.appendChild(el.cloneNode(true)); // 克隆节点并保留所有属性和子节点
  const style = document.createElement("style");
  style.innerHTML =
    "body>#" +
    printId +
    "{display:none}@media print{" +
    "@page {" +
    "    size: auto; " +
    "    margin: 13mm 4mm 0mm 4mm; " +
    "  }body>:not(#" +
    printId +
    "){display:none !important}body>#" +
    printId +
    "{display:block;padding-top:1px}}";
  body.appendChild(style);
  body.appendChild(content);
  // 优化分页逻辑
  const layoutWrappers = content.querySelectorAll('.layout-wrapper');
  let currentPageHeight = 0;
  let currentWrapperIndex = 0;
  layoutWrappers.forEach((wrapper, index) => {
    const wrapperHeight = wrapper.offsetHeight;
    if (currentPageHeight + wrapperHeight > props.fixedPageHeight) {
      const pageBreak = document.createElement('div');
      pageBreak.className = 'element-to-break-after';
      layoutWrappers[currentWrapperIndex - 1].appendChild(pageBreak);
      currentPageHeight = wrapperHeight;
    } else {
      currentPageHeight += wrapperHeight;
    }
    currentWrapperIndex = index + 1;
  });
  setTimeout(() => {
    window.print();
    body.removeChild(content);
    body.removeChild(style);
  }, 200);
};
defineExpose({
  print,
  updateLayout
});
</script>
<style scoped>
@media print {
  .layout-wrapper {
    page-break-inside: avoid;
    margin-bottom: 20px;
  }
  .element-to-break-after {
    page-break-after: always;
  }
  .header {
    position: static;
    width: 100%;
  }
  .layout-container {
    position: static;
    width: 100%;
    height: auto;
  }
  .grid-container {
    display: grid;
    gap: 10px; /* 减少打印时的网格间距 */
  }
  .cols-1 {
    grid-template-columns: 1fr;
  }
  .cols-2 {
    grid-template-columns: repeat(2, 1fr);
  }
  .cols-3 {
    grid-template-columns: repeat(3, 1fr);
  }
  .cols-4 {
    grid-template-columns: repeat(4, 1fr);
  }
}
.element-to-break-after {
  page-break-after: always;
}
.layout-wrapper {
  position: relative;
  margin-top: 50px;
}
.header {
  position: absolute;
  top: -45px;
  left: 0;
  width: 100%;
  text-align: center;
  z-index: 1000;
  background-color: #ffffff;
  padding: 5px;
  font-size: 12px;
}
.layout-container {
  position: relative;
  overflow: visible;
}
.layout-info {
  color: #444;
  font-size: 12px;
  background-color: #ffffff;
  padding: 5px 10px;
  border-radius: 3px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  font-weight: bold;
}
.rect-content {