<template>
|
<div ref="layoutPanel" id="printFlowCard" :class="panelClass" :style="panelStyle">
|
<div v-if="dataLoadeds">
|
<h3>工程号【{{ processId }}】</h3>
|
</div>
|
<div
|
v-for="(layout, layoutIndex) in layouts"
|
:key="layoutIndex"
|
class="layout-wrapper"
|
:style="titleStyle(layoutIndex)"
|
v-if="dataLoaded"
|
>
|
<!-- Layout Info Label -->
|
<div class="layout-info" :style="layoutInfoStyle(layoutIndex)">
|
工程号{{ processId }}
|
{{ getCurrentRectInfo(layoutIndex) }}
|
</div>
|
|
<!-- Layout Container -->
|
<div class="layout-container" :style="layoutContainerStyle1(layoutIndex)">
|
<div class="layout-container" :style="layoutContainerStyle(layoutIndex)">
|
<!-- 灰色矩形 -->
|
<div
|
v-for="(glassDetail, rectIndex) in layout.glassDetails.filter(r => r.isRemain)"
|
:key="`gray-${rectIndex}`"
|
:ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
|
class="layout-glassDetail"
|
:style="rectStyle1(glassDetail, layoutIndex)"
|
>
|
<!-- <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="(glassDetail, rectIndex) in layout.glassDetails.filter(r => !r.isRemain)"
|
:key="`blue-${rectIndex}`"
|
:ref="(el) => { if (el) rectsElements[layoutIndex + '-' + rectIndex] = el }"
|
class="layout-glassDetail"
|
:style="rectStyle(glassDetail, layoutIndex)"
|
>
|
<div class="glassDetail-content">
|
<div class="size">{{ glassDetail.realWidth }}×{{ glassDetail.realHeight }}</div>
|
<div>{{glassDetail.polySort }}</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
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: 1400 },
|
gh: { type: Number, default: 800 },
|
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 }, // 固定页面高度
|
materialDetails:null,
|
state:null,
|
projectNo: { type: [String, Number], default: null }
|
});
|
|
const emit = defineEmits(['rectClicked']);
|
const layoutPanel = ref(null);
|
const rectsElements = ref({});
|
const focusIndex = ref(null);
|
const layouts = ref([]);
|
const materialDetails = ref([]);
|
const panelClass = ref('');
|
const panelStyle = ref(props.style);
|
const rectClass = ref('layout-glassDetail');
|
const processId = ref();
|
const printColumns = ref(2); // 初始化为2列
|
const layoutsPerPage = ref(4); // 默认每页显示4个布局(2行×2列)
|
const selectedLayoutIndex = ref(0);
|
const layoutDetails = ref([]);
|
const dataLoaded = ref(false);
|
const dataLoadeds = ref(false);
|
const scale = 0.1;
|
let tops = 0;
|
let lefts = 0;
|
|
// 定义不同布局的放大比例
|
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 titleStyle = (layoutIndex) => {
|
const layout = layouts.value[layoutIndex-1];
|
if(layoutIndex<2){
|
if(layoutIndex===0){
|
tops = 0;
|
lefts = 0;
|
}else{
|
lefts = "50%";
|
}
|
}else{
|
if(layoutIndex%2===0){
|
tops = tops+layout.height*scale+50;
|
lefts=0;
|
}else{
|
lefts = "50%";
|
}
|
}
|
|
return {
|
width: `50%`,
|
left: `${lefts}`,
|
top: `${tops}px`,
|
};
|
};
|
|
const layoutContainerStyle = (layoutIndex) => {
|
const layout = layouts.value[layoutIndex];
|
// const scale = Math.min(0.25); // 增大比例
|
|
return {
|
position: 'absolute',
|
left: `${layout.leftTrim * scale}px`,
|
top: `${layout.upTrim * scale}px`,
|
width: `${layout.width * scale}px`,
|
height: `${layout.height * scale}px`,
|
overflow: 'visible',
|
//border: '1px solid #ccc',
|
background: '#fff'
|
};
|
};
|
|
const layoutContainerStyle1 = (layoutIndex) => {
|
const layout = layouts.value[layoutIndex];
|
// const scale = Math.min(0.25); // 增大比例
|
return {
|
position: 'absolute',
|
left: `20px`,
|
top: `40px`,
|
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: `40px`,
|
top: `0px`,
|
textAlign: 'center',
|
zIndex: 1000,
|
background: '#ffffff',
|
padding: '5px',
|
fontSize: '15px'
|
};
|
};
|
|
//版图内容小片样式加载
|
const rectStyle = (glassDetail, layoutIndex) => {
|
const layout = layouts.value[layoutIndex];
|
// const scale = Math.min(0.25); // 增大比例
|
return {
|
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' : '#a0d8ef',
|
border: '1px solid #000',
|
cursor: 'pointer',
|
draggable: !glassDetail.isRemain,
|
zIndex: glassDetail.isRemain ? 1 : 2
|
};
|
};
|
|
const rectStyle1 = (glassDetail, layoutIndex) => {
|
const layout = layouts.value[layoutIndex];
|
// const scale = Math.min(0.25); // 增大比例
|
return {
|
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' : '#a0d8ef',
|
border: '1px solid #000',
|
cursor: 'pointer',
|
draggable: !glassDetail.isRemain,
|
zIndex: glassDetail.isRemain ? 1 : 2
|
};
|
};
|
|
|
const handleRectClick = (layoutIndex, rectIndex) => {
|
focusIndex.value = { layoutIndex, rectIndex };
|
emit('rectClicked', layoutIndex, rectIndex);
|
};
|
|
const getCurrentRectInfo = (layoutIndex) => {
|
const layout = layouts.value[layoutIndex];
|
const totalRects = layouts.value.length;
|
const currentRectIndex = layoutIndex + 1;
|
const width = layout.realWidth;
|
const height = layout.realHeight;
|
const sum = layout.glassDetails.reduce((sum, r) => sum + (width * height), 0);
|
const percentage = (layout.usageRate * 100).toFixed(2) + '%';
|
return `${currentRectIndex}/${totalRects} ${width}X${height}X${layout.quantity} ${percentage}`;
|
};
|
|
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;
|
|
if (!props.layoutData) {
|
console.warn('layoutData 为空');
|
return;
|
}
|
|
console.log('RectRenderer 接收到的 layoutData:', props.layoutData);
|
processId.value=props.layoutData.projectNo;
|
// 处理 layouts 数据
|
if (props.layoutData.layouts && Array.isArray(props.layoutData.layouts)) {
|
let originalFilm = [];
|
|
props.layoutData.layouts.forEach(items => {
|
const existingItem = originalFilm.find(item => item.mergeId === items.mergeId);
|
if (existingItem) {
|
existingItem.quantity += 1;
|
} else {
|
originalFilm.push(items);
|
}
|
});
|
|
layouts.value = originalFilm;
|
layoutDetails.value.push(props.layoutData);
|
materialDetails.value = props.materialDetails;
|
console.log('处理后的 layouts:', layouts.value);
|
} else {
|
console.warn('layouts 数据格式不正确或为空');
|
}
|
|
// 确保数据加载状态正确设置
|
if (processId.value) {
|
dataLoaded.value = true;
|
dataLoadeds.value = true;
|
}
|
|
adjustPrintLayout();
|
layoutPanel.value.offsetHeight; // 触发布局更新
|
};
|
|
onMounted(() => {
|
if(props.state===2||props.state===0){
|
dataLoaded.value=true
|
}
|
if(props.state>0){
|
dataLoadeds.value=true
|
}
|
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;
|
display: block;
|
}
|
|
.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;
|
}
|
|
.glassDetail-content {
|
display: grid;
|
grid-template-columns: 1fr;
|
grid-template-rows: 1fr;
|
padding: 5px;
|
}
|
|
.size {
|
grid-row: 1;
|
grid-column: 1;
|
color: #444;
|
font-size: 12px;
|
}
|
|
.jia-hao {
|
grid-row: 2;
|
grid-column: 1;
|
margin: auto;
|
font-size: 14px;
|
font-weight: bold;
|
}
|
</style>
|