| | |
| | | } |
| | | }, |
| | | "node_modules/@babel/helper-string-parser": { |
| | | "version": "7.22.5", |
| | | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", |
| | | "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", |
| | | "version": "7.25.9", |
| | | "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", |
| | | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", |
| | | "engines": { |
| | | "node": ">=6.9.0" |
| | | } |
| | | }, |
| | | "node_modules/@babel/helper-validator-identifier": { |
| | | "version": "7.22.20", |
| | | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", |
| | | "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", |
| | | "version": "7.25.9", |
| | | "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", |
| | | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", |
| | | "engines": { |
| | | "node": ">=6.9.0" |
| | | } |
| | | }, |
| | | "node_modules/@babel/parser": { |
| | | "version": "7.23.0", |
| | | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", |
| | | "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", |
| | | "version": "7.27.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.0.tgz", |
| | | "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", |
| | | "dependencies": { |
| | | "@babel/types": "^7.27.0" |
| | | }, |
| | | "bin": { |
| | | "parser": "bin/babel-parser.js" |
| | | }, |
| | |
| | | "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" |
| | | }, |
| | | "node_modules/@babel/types": { |
| | | "version": "7.23.0", |
| | | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", |
| | | "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", |
| | | "version": "7.27.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.0.tgz", |
| | | "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", |
| | | "dependencies": { |
| | | "@babel/helper-string-parser": "^7.22.5", |
| | | "@babel/helper-validator-identifier": "^7.22.20", |
| | | "to-fast-properties": "^2.0.0" |
| | | "@babel/helper-string-parser": "^7.25.9", |
| | | "@babel/helper-validator-identifier": "^7.25.9" |
| | | }, |
| | | "engines": { |
| | | "node": ">=6.9.0" |
| | |
| | | "utrie": "^1.0.2" |
| | | } |
| | | }, |
| | | "node_modules/to-fast-properties": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", |
| | | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", |
| | | "engines": { |
| | | "node": ">=4" |
| | | } |
| | | }, |
| | | "node_modules/to-regex-range": { |
| | | "version": "5.0.1", |
| | | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", |
| | |
| | | }, |
| | | "dependencies": { |
| | | "@babel/helper-string-parser": { |
| | | "version": "7.22.5", |
| | | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", |
| | | "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" |
| | | "version": "7.25.9", |
| | | "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", |
| | | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==" |
| | | }, |
| | | "@babel/helper-validator-identifier": { |
| | | "version": "7.22.20", |
| | | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", |
| | | "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" |
| | | "version": "7.25.9", |
| | | "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", |
| | | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==" |
| | | }, |
| | | "@babel/parser": { |
| | | "version": "7.23.0", |
| | | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", |
| | | "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" |
| | | "version": "7.27.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.0.tgz", |
| | | "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", |
| | | "requires": { |
| | | "@babel/types": "^7.27.0" |
| | | } |
| | | }, |
| | | "@babel/runtime": { |
| | | "version": "7.26.10", |
| | |
| | | } |
| | | }, |
| | | "@babel/types": { |
| | | "version": "7.23.0", |
| | | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", |
| | | "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", |
| | | "version": "7.27.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.0.tgz", |
| | | "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", |
| | | "requires": { |
| | | "@babel/helper-string-parser": "^7.22.5", |
| | | "@babel/helper-validator-identifier": "^7.22.20", |
| | | "to-fast-properties": "^2.0.0" |
| | | "@babel/helper-string-parser": "^7.25.9", |
| | | "@babel/helper-validator-identifier": "^7.25.9" |
| | | } |
| | | }, |
| | | "@claviska/jquery-minicolors": { |
| | |
| | | }, |
| | | "dependencies": { |
| | | "@babel/helper-string-parser": { |
| | | "version": "7.22.5", |
| | | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", |
| | | "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" |
| | | "version": "7.25.9", |
| | | "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", |
| | | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==" |
| | | }, |
| | | "@babel/helper-validator-identifier": { |
| | | "version": "7.22.20", |
| | | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", |
| | | "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" |
| | | "version": "7.25.9", |
| | | "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", |
| | | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==" |
| | | }, |
| | | "@babel/parser": { |
| | | "version": "7.23.0", |
| | | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", |
| | | "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" |
| | | "version": "7.27.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.0.tgz", |
| | | "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", |
| | | "requires": { |
| | | "@babel/types": "^7.27.0" |
| | | } |
| | | }, |
| | | "@babel/runtime": { |
| | | "version": "7.26.10", |
| | |
| | | } |
| | | }, |
| | | "@babel/types": { |
| | | "version": "7.23.0", |
| | | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", |
| | | "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", |
| | | "version": "7.27.0", |
| | | "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.0.tgz", |
| | | "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", |
| | | "requires": { |
| | | "@babel/helper-string-parser": "^7.22.5", |
| | | "@babel/helper-validator-identifier": "^7.22.20", |
| | | "to-fast-properties": "^2.0.0" |
| | | "@babel/helper-string-parser": "^7.25.9", |
| | | "@babel/helper-validator-identifier": "^7.25.9" |
| | | } |
| | | }, |
| | | "@claviska/jquery-minicolors": { |
| | |
| | | "requires": { |
| | | "utrie": "^1.0.2" |
| | | } |
| | | }, |
| | | "to-fast-properties": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", |
| | | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" |
| | | }, |
| | | "to-regex-range": { |
| | | "version": "5.0.1", |
| | |
| | | "requires": { |
| | | "utrie": "^1.0.2" |
| | | } |
| | | }, |
| | | "to-fast-properties": { |
| | | "version": "2.0.0", |
| | | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", |
| | | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" |
| | | }, |
| | | "to-regex-range": { |
| | | "version": "5.0.1", |
| | |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | path: '/main/glassOptimize/MoveManage', |
| | | component: () => import('@/views/pp/glassOptimize/MoveManage.vue') |
| | | }, |
| | | { |
| | | path:'userPassWord', |
| | | name: 'userPassWord', |
| | |
| | | <template>
|
| | | <div>
|
| | | <RectRenderer
|
| | | v-if="dataLoaded"
|
| | | :layoutData="layoutData"
|
| | | :gw="1150"
|
| | | :gh="850"
|
| | |
| | | import { ElMessage } from "element-plus";
|
| | |
|
| | | const { t } = useI18n();
|
| | | //const layoutData = ref(mockLayoutData);
|
| | | // const processId = "P25030309";
|
| | | const savedProjectNo = localStorage.getItem('projectNo');
|
| | | const processId = savedProjectNo;
|
| | | console.log(processId)
|
| | | const layoutData = ref(null);
|
| | | const dataLoaded = ref(false);
|
| | |
|
| | | const selectLayout = () => {
|
| | | request.post(`/glassOptimize/selectOptimizeResult/${processId}`)
|
| | | .then((res) => {
|
| | | if (res.code == 200) {
|
| | | try {
|
| | | // 将字符串数据转换为对象
|
| | | // console.log("原始数据:", res.data.data[0].Layouts);
|
| | |
|
| | | const parsedData = JSON.parse(res.data.data[0].Layouts);
|
| | | layoutData.value = parsedData;
|
| | | // console.log("解析后的数据:", layoutData.value);
|
| | | // console.log("数据类型:", typeof parsedData);
|
| | | ElMessage.success("打开版图成功")
|
| | | dataLoaded.value = true;
|
| | | ElMessage.success("打开版图成功");
|
| | | } catch (error) {
|
| | | ElMessage.error("解析数据时出错:", error);
|
| | | |
| | | }
|
| | | } else {
|
| | |
|
| | | ElMessage.error(t('basicData.msg.requestFailed'));
|
| | | }
|
| | | })
|
| | | .catch((error) => {
|
| | |
| | |
|
| | | onMounted(() => {
|
| | | selectLayout();
|
| | |
|
| | | });
|
| | | </script>
|
| | |
| | | <template> |
| | | <div> |
| | | |
| | | <el-button id="button" type="primary" @click="handlePrint">打印版图</el-button> |
| | | <el-select |
| | | v-model="printLayout" |
| | | placeholder="选择打印布局" |
| | | @change="handleLayoutChange" |
| | | style="width: 150px; margin-bottom: 10px;"> |
| | | <el-option label="四行两列" value="4rows-2cols"></el-option> |
| | | <el-option label="三行两列" value="3rows-2cols"></el-option> |
| | | <el-option label="三行一列" value="3rows-1col"></el-option> |
| | | <el-option label="两行两列" value="2rows-2cols"></el-option> |
| | | </el-select> |
| | | |
| | | <div ref="printContainer" style="position: relative;"> |
| | | <RectRenderer |
| | | ref="rectRenderer" |
| | | :layoutData="layoutData" |
| | | :gw="1400" |
| | | :gh="1100" |
| | | style="width: 100%; height: 800px; position: relative;" |
| | | :gw="currentGw" |
| | | :gh="currentGh" |
| | | :printLayout="printLayout" |
| | | :printWidth="currentPrintWidth" |
| | | :printHeight="currentPrintHeight" |
| | | style="position: absolute;" |
| | | v-if="dataLoaded" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref,onMounted } from 'vue'; |
| | | import { ref, onMounted, watch } from 'vue'; |
| | | import RectRenderer from './page/RectRenderer.vue'; |
| | | import mockLayoutData from '../../../components/pp/MockData'; |
| | | import request from "@/utils/request"; |
| | | import { useI18n } from "vue-i18n"; |
| | | //const layoutData = ref(mockLayoutData); |
| | | const rectRenderer = ref(null); |
| | | |
| | | const printLayout = ref('2rows-2cols'); |
| | | const rectRenderer = ref(null); |
| | | const savedProjectNo = localStorage.getItem('projectNo'); |
| | | const processId = savedProjectNo; |
| | | const layoutData = ref(null); |
| | | const dataLoaded = ref(false); |
| | | // 定义不同布局对应的尺寸 |
| | | const layoutDimensions = { |
| | | '4rows-2cols': { width: 1000, height: 1000 }, |
| | | '3rows-2cols': { width: 1000, height: 1000 }, |
| | | '3rows-1col': { width: 1000, height: 1000 }, |
| | | '2rows-2cols': { width: 1200, height: 1200 } |
| | | }; |
| | | |
| | | |
| | | // 当前布局的尺寸 |
| | | const currentGw = ref(layoutDimensions[printLayout.value].width); |
| | | const currentGh = ref(layoutDimensions[printLayout.value].height); |
| | | const currentPrintWidth = ref(layoutDimensions[printLayout.value].width); |
| | | const currentPrintHeight = ref(layoutDimensions[printLayout.value].height); |
| | | |
| | | const selectLayout = () => { |
| | | request.post(`/glassOptimize/selectOptimizeResult/${processId}`) |
| | |
| | | try { |
| | | const parsedData = JSON.parse(res.data.data[0].Layouts); |
| | | layoutData.value = parsedData; |
| | | dataLoaded.value = true; |
| | | } catch (error) { |
| | | |
| | | |
| | | console.error("解析布局数据失败:", error); |
| | | } |
| | | } else { |
| | | |
| | | console.error("请求失败,状态码:", res.code); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error("请求失败:", error); |
| | | ElMessage.error(t('basicData.msg.requestFailed')); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | selectLayout(); |
| | | |
| | | }); |
| | | |
| | | |
| | | const handlePrint = () => { |
| | | // 创建一个隐藏的iframe |
| | | const iframe = document.createElement('iframe'); |
| | | iframe.style.position = 'fixed'; |
| | | iframe.style.top = '-100vh'; |
| | | iframe.style.left = '-100vw'; |
| | | iframe.style.width = '200%'; |
| | | iframe.style.height = '200%'; |
| | | document.body.appendChild(iframe); |
| | | |
| | | // 将RectRenderer的内容加载到iframe中 |
| | | const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; |
| | | iframeDoc.open(); |
| | | iframeDoc.write(` |
| | | <html> |
| | | <head> |
| | | <title>Print Layout</title> |
| | | <style> |
| | | @page { |
| | | size: A4 landscape; |
| | | margin: 20mm; |
| | | if (rectRenderer.value) { |
| | | rectRenderer.value.print(); |
| | | } |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | .layout-wrapper { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .layout-container { |
| | | page-break-inside: avoid; |
| | | break-inside: avoid; |
| | | page-break-after: auto; |
| | | margin-bottom: 20mm; |
| | | } |
| | | .layout-item { |
| | | page-break-inside: avoid; |
| | | break-inside: avoid; |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | <div class="layout-wrapper"> |
| | | ${rectRenderer.value.$el.outerHTML} |
| | | </div> |
| | | </body> |
| | | </html> |
| | | `); |
| | | iframeDoc.close(); |
| | | |
| | | // 设置打印样式 |
| | | const printStyle = iframeDoc.createElement('style'); |
| | | printStyle.type = 'text/css'; |
| | | printStyle.innerHTML = ` |
| | | @page { |
| | | size: A4 landscape; |
| | | margin: 20mm; |
| | | } |
| | | body { |
| | | -webkit-print-color-adjust: exact; |
| | | } |
| | | .layout-wrapper { |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .layout-container { |
| | | page-break-inside: avoid; |
| | | break-inside: avoid; |
| | | page-break-after: auto; |
| | | margin-bottom: 20mm; |
| | | } |
| | | .layout-item { |
| | | page-break-inside: avoid; |
| | | break-inside: avoid; |
| | | } |
| | | `; |
| | | iframeDoc.head.appendChild(printStyle); |
| | | |
| | | // 调整iframe大小以适应内容 |
| | | const contentWidth = rectRenderer.value.$el.offsetWidth; |
| | | const contentHeight = rectRenderer.value.$el.offsetHeight; |
| | | iframe.width = contentWidth + 'px'; |
| | | iframe.height = contentHeight + 'px'; |
| | | |
| | | // 执行打印 |
| | | iframe.contentWindow.print(); |
| | | |
| | | // 清理 |
| | | setTimeout(() => { |
| | | document.body.removeChild(iframe); |
| | | }, 100); |
| | | }; |
| | | |
| | | const handleLayoutChange = () => { |
| | | // 更新布局尺寸 |
| | | const dimensions = layoutDimensions[printLayout.value]; |
| | | currentGw.value = dimensions.width; |
| | | currentGh.value = dimensions.height; |
| | | currentPrintWidth.value = dimensions.width; |
| | | currentPrintHeight.value = dimensions.height; |
| | | |
| | | if (rectRenderer.value) { |
| | | rectRenderer.value.updateLayout(); |
| | | } |
| | | }; |
| | | |
| | | // 监听布局变化 |
| | | watch(printLayout, (newVal) => { |
| | | handleLayoutChange(); |
| | | }); |
| | | </script> |
| | |
| | | :gw="1400"
|
| | | :gh="1100"
|
| | | style="width: 1500px; height: 800px; position: relative;"
|
| | | v-if="dataLoaded"
|
| | | />
|
| | |
|
| | |
|
| | |
| | | const { t } = useI18n();
|
| | | // const layoutData = ref(mockLayoutData);
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | | const savedProjectNo = localStorage.getItem('projectNo');
|
| | | const processId = savedProjectNo;
|
| | | const layoutData = ref(null);
|
| | |
|
| | | const dataLoaded = ref(false);
|
| | |
|
| | |
|
| | | const selectLayout = () => {
|
| | |
| | | try {
|
| | | const parsedData = JSON.parse(res.data.data[0].Layouts);
|
| | | layoutData.value = parsedData;
|
| | | dataLoaded.value = true;
|
| | | } catch (error) {
|
| | |
|
| | |
|
| | |
| | | return;
|
| | | }
|
| | | const parsedData = JSON.parse(response.data);
|
| | | 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) {
|
| | |
| | | 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);
|
| | |
| | | contextMenu.appendChild(moveRightItem);
|
| | | contextMenu.appendChild(deleteItem);
|
| | | contextMenu.appendChild(addItem);
|
| | | contextMenu.appendChild(mirrorXItem);
|
| | | contextMenu.appendChild(mirrorYItem);
|
| | |
|
| | | document.body.appendChild(contextMenu);
|
| | | };
|
| | |
| | | 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);
|
| | | };
|
| | |
| | |
|
| | | rect.x = Math.round(rect.x);
|
| | | rect.y = Math.round(rect.y);
|
| | | //adjustAlignmentPosition(layoutIndex, rectIndex);
|
| | | adjustAlignmentPosition(layoutIndex, rectIndex);
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | }
|
| | |
|
| | |
| | | // 调整后重新计算灰色余料
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | };
|
| | |
|
| | |
|
| | | const mergeAdjacentGrayRects = (rects) => {
|
| | | const grayRects = rects.filter(r => r.isRemain);
|
| | |
| | |
|
| | | otherRects.forEach(otherRect => {
|
| | | if (checkOverlap(rect, otherRect)) {
|
| | | isValidRotation = false }
|
| | | isValidRotation = false;
|
| | | }
|
| | | });
|
| | |
|
| | | if (rect.x + rect.w > layout.width || rect.y + rect.h > layout.height) {
|
| | |
| | | }
|
| | | };
|
| | |
|
| | | const mirrorLayoutX = (layoutIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const width = layout.width;
|
| | | const rects = [...layout.rects]; // 创建副本避免直接修改
|
| | |
|
| | | rects.forEach(rect => {
|
| | | // 计算X镜像后的坐标
|
| | | const newX = width - rect.x - rect.w;
|
| | | const newY = rect.y;
|
| | |
|
| | | // 更新矩形位置
|
| | | rect.x = newX;
|
| | | rect.y = newY;
|
| | | });
|
| | |
|
| | | // 更新布局
|
| | | layout.rects = rects;
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | };
|
| | |
|
| | | const mirrorLayoutY = (layoutIndex) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const height = layout.height;
|
| | | const rects = [...layout.rects]; // 创建副本避免直接修改
|
| | |
|
| | | rects.forEach(rect => {
|
| | | // 计算Y镜像后的坐标
|
| | | const newX = rect.x;
|
| | | const newY = height - rect.y - rect.h;
|
| | |
|
| | | // 更新矩形位置
|
| | | rect.y = newY;
|
| | | });
|
| | |
|
| | | // 更新布局
|
| | | layout.rects = rects;
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | };
|
| | |
|
| | | onMounted(() => {
|
| | | fetchSettings(username);
|
| | | setTimeout(updateLayout, 500);
|
| | | updateLayout();
|
| | |
|
| | | selectedLayoutIndex.value = 0;
|
| | |
|
| | |
| | | document.addEventListener('keyup', handleKeyUp);
|
| | | });
|
| | |
|
| | |
|
| | |
|
| | | onUnmounted(() => {
|
| | | rectsElements.value = {};
|
| | | if (clickEventListener) {
|
| | |
| | | document.removeEventListener('keydown', handleKeyDown);
|
| | | document.removeEventListener('keyup', handleKeyUp);
|
| | | });
|
| | |
|
| | | </script>
|
| | |
|
| | |
|
| | | <style scoped>
|
| | | .layout-wrapper {
|
| | |
| | | }
|
| | |
|
| | | .rect-content {
|
| | | display: grid;
|
| | | grid-template-columns: 1fr;
|
| | | grid-template-rows: 1fr;
|
| | | 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;
|
| | | font-size: 14px;
|
| | | font-weight: bold;
|
| | | white-space: normal;
|
| | | word-wrap: break-word;
|
| | | }
|
| | |
|
| | | .sidebar-item {
|
| | |
| | | <template>
|
| | | <div ref="layoutPanel" :class="panelClass" :style="panelStyle">
|
| | | <div id="printFlowCard">
|
| | | <div v-for="(layout, layoutIndex) in layouts" :key="layoutIndex" class="layout-wrapper">
|
| | | <!-- 布局信息标签 -->
|
| | | <div class="layout-info" :style="layoutInfoStyle(layoutIndex)">
|
| | | <div class="header" :style="headerStyle(layoutIndex)">
|
| | | 工程号{{ processId }}
|
| | | {{ getCurrentRectInfo(layoutIndex) }}
|
| | | </div>
|
| | |
|
| | | <!-- 布局容器 -->
|
| | | <div class="layout-container" :style="layoutContainerStyle(layoutIndex)">
|
| | | <div v-for="(rect, rectIndex) in layout.rects" :key="rectIndex"
|
| | | <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)">
|
| | | @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>
|
| | | </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']);
|
| | |
| | | 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`,
|
| | |
| | | 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`,
|
| | |
| | | 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 {
|