Merge branch 'master' of http://10.153.19.25:10101/r/ERP_override
| | |
| | | } |
| | | }, |
| | | "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", |
| | |
| | | produceList1.otherMoney1=otherMoney1 |
| | | produceList2.value.push(produceList1) |
| | | } |
| | | for(let j=0;j<produceList2.value.length;j++){ |
| | | |
| | | if(produceList2.value[j].delivery.money.toFixed(0)!==(produceList2.value[j].otherMoneys |
| | | +produceList2.value[j].sumMoney+produceList2.value[j].delivery.freight).toFixed(0)){ |
| | | console.log(produceList2.value[j]) |
| | | console.log(produceList2.value[j].delivery.money) |
| | | console.log((produceList2.value[j].otherMoneys |
| | | +produceList2.value[j].sumMoney).toFixed(0)) |
| | | console.log(produceList2.value[j].delivery.deliveryId) |
| | | } |
| | | |
| | | } |
| | | |
| | | }else{ |
| | | ElMessage.warning(res.msg) |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | const props = defineProps({ |
| | | projectNo : String |
| | | project : null |
| | | }); |
| | | |
| | | const computed = ref(null); |
| | |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | if (props.projectNo) { |
| | | handleFetchData(props.projectNo); |
| | | handleTableData(data); |
| | | handleDataReceive(data); |
| | | if (props.project) { |
| | | handleFetchData(props.project.projectNumber); |
| | | //handleTableData(data); |
| | | //handleDataReceive(data); |
| | | } |
| | | }); |
| | | |
| | |
| | | <div style="width: 100%; height: 100%;"> |
| | | |
| | | <div id="compute"> |
| | | <compute :data="computedData" @fetch-data="handleFetchData" :project-no="props.projectNo" @sendData="handleData" @simulate-click="handleSimulation" /> |
| | | <compute :data="computedData" @fetch-data="handleFetchData" :project="props.project" @sendData="handleData" @simulate-click="handleSimulation" /> |
| | | </div> |
| | | |
| | | <div id="computeCard"> |
| | |
| | | margin-top: -30px; |
| | | margin-bottom: 2%; |
| | | width: 100%; |
| | | height: 40%; |
| | | height: 37%; |
| | | } |
| | | #computeCard{ |
| | | margin-top: 90px; |
| | | width: 64%; |
| | | height: 40%; |
| | | height: 55%; |
| | | float: left; |
| | | } |
| | | #computeDetail{ |
| | | margin-top: 90px; |
| | | margin-left: 1%; |
| | | float: left; |
| | | width: 35%; |
| | | height: 40%; |
| | | height: 55%; |
| | | } |
| | | </style> |
| | |
| | | <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) {
|
| | |
|
| | |
|
| | |
| | | } |
| | | |
| | | //从工程管理获取工程号,并跳转 |
| | | const projectNumber = ref(''); |
| | | const projectNumber = ref(); |
| | | const switchDialog = (number) => { |
| | | projectNumber.value = number; |
| | | detailPage.value = 3; |
| | |
| | | style="width: 90%;height:90%;margin-top: 3vh" |
| | | z-index="100" |
| | | > |
| | | <project-create v-if="detailPage===1" /> |
| | | <project-create v-if="detailPage===1" @switch-dialog="switchDialog"/> |
| | | <project-mange v-if="detailPage===2" @switch-dialog="switchDialog" @closeDetailPage="handlePopupClose"/> |
| | | <glass-computed v-if="detailPage===3" :project-no="projectNumber"/> |
| | | <glass-computed v-if="detailPage===3" :project="projectNumber"/> |
| | | <div v-else></div> |
| | | </el-dialog> |
| | | |
| | |
| | | :deep( .el-dialog__body){ |
| | | height: calc(100% - 55px); |
| | | width: 100%; |
| | | margin-top: 30px; |
| | | //padding: 0; |
| | | } |
| | | |
| | |
| | | import ProcessCardDetail from "@/views/pp/glassOptimize/page/ProcessCardDetail.vue"; |
| | | import ProjectList from "@/views/pp/glassOptimize/page/ProjectList.vue"; |
| | | |
| | | import {ref} from "vue"; |
| | | import {defineEmits, nextTick, onMounted, reactive, ref} from "vue"; |
| | | import {useI18n} from "vue-i18n"; |
| | | import GlassComputed from "@/views/pp/glassOptimize/GlassComputed.vue"; |
| | | import ProjectMange from "@/views/pp/glassOptimize/ProjectMange.vue"; |
| | | import request from "@/utils/request"; |
| | | import {ElMessage, ElMessageBox} from "element-plus"; |
| | | import deepClone from "@/utils/deepClone"; |
| | | |
| | | let projectRow = ref({ |
| | | processId:null, |
| | | technologyNumber:null |
| | | }) |
| | | |
| | | const processCardRef=ref(null) |
| | | |
| | | const handleProcessIdUpdate = newProcessId => { |
| | | projectRow.value.processId = newProcessId; |
| | | |
| | | }; |
| | | |
| | | const handleTechnologyNumberUpdate = newTechnologyNumber => { |
| | | projectRow.value.technologyNumber = newTechnologyNumber; |
| | | }; |
| | | |
| | | const updateState = state => { |
| | | getProject(); |
| | | |
| | | }; |
| | | |
| | | |
| | | const { t } = useI18n() |
| | | |
| | | const xGrid = ref() |
| | | |
| | | |
| | | const gridOptions = reactive({ |
| | | height:'100%', |
| | | loading: false, |
| | | border: "full",//表格加边框 |
| | | keepSource: true,//保持源数据 |
| | | align: 'center',//文字居中 |
| | | stripe:true,//斑马纹 |
| | | rowConfig: {isCurrent: true, isHover: true,height: 30, useKey: true},//鼠标移动或选择高亮 |
| | | id: 'ProjectList', |
| | | scrollX:{enabled: true}, |
| | | scrollY:{ enabled: true ,gt:0},//开启虚拟滚动 |
| | | showOverflow:true, |
| | | columnConfig: { |
| | | resizable: true, |
| | | useKey: true |
| | | }, |
| | | filterConfig: { //筛选配置项 |
| | | remote: true |
| | | }, |
| | | customConfig: { |
| | | storage: true |
| | | }, |
| | | editConfig: { |
| | | trigger: 'click', |
| | | mode: 'row', |
| | | showStatus: true |
| | | }, |
| | | columns:[ |
| | | {field: 'id',width: 150, title: 'ID',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'projectNumber',width: 150, title: '工程号',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'project_name',width: 150, title: '项目名称',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'glass_type',width: 150, title: '膜系',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'glass_thickness',width: 150, title: '厚度',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'type',width: 150, title: '类型',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'state',width: 150, title: '状态',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'quantity',width: 150, title: t('order.quantity'),filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'glass_total_area',width: 150, title: t('order.grossArea'),filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'process_qty',width: 150, title: '流程数量',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'process_cards',width: 150, title: '流程卡号',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | |
| | | ],//表头参数 |
| | | data:null,//表格数据 |
| | | toolbarConfig: { |
| | | buttons: [ |
| | | ], |
| | | import: false, |
| | | // export: true, |
| | | // print: true, |
| | | zoom: true, |
| | | custom: true |
| | | }, |
| | | //右键菜单选项 |
| | | menuConfig: { |
| | | body: { |
| | | options: [ |
| | | [ |
| | | {code: 'openProject', name: '打开工程', prefixIcon: 'vxe-icon-folder-open'}, |
| | | {code: 'compute', name: '模拟计算', prefixIcon: 'vxe-icon-subtable'}, |
| | | {code: 'delProject', name: '删除工程', prefixIcon: 'vxe-icon-delete'}, |
| | | ], |
| | | [] |
| | | ] |
| | | } |
| | | } |
| | | |
| | | }) |
| | | |
| | | // 定义操作配置对象数组,集中管理不同操作选项对应的参数 |
| | | const operationConfigs = [ |
| | | { |
| | | code: 'openProject', // 打开工程 |
| | | initialState: ['10', '20', '100', '200'], // |
| | | targetState: null, |
| | | successMsg: '已打开!', |
| | | checkMessage: '当前工程状态不符合条件,请确认工程状态后再操作!', |
| | | requiresRow: true, |
| | | openFile: async ({row}) => { |
| | | const projectNumber = row.projectNumber; |
| | | const thickness = row.thickness; |
| | | const glassType = row.glassType; |
| | | await router.push({ |
| | | name: 'optimizeInfo', |
| | | params: { |
| | | projectNo: projectNumber, |
| | | thickNess: thickness, |
| | | model: glassType |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | { |
| | | code: 'compute', // 打开模拟计算操作 |
| | | initialState: ['1'], // |
| | | targetState: null, |
| | | successMsg: '模拟计算已启动!', |
| | | checkMessage: '当前工程状态不符合模拟计算条件,请确认工程状态后再操作!', |
| | | requiresRow: true, |
| | | actionFunction: async ({row}) => { |
| | | const projectNo = row.projectNumber; |
| | | emit('switch-dialog', row); |
| | | } |
| | | }, |
| | | { |
| | | code: 'delProject', |
| | | initialState: ['1'], |
| | | targetState: null, |
| | | successMsg: '工程删除成功!', |
| | | checkMessage: '当前工程状态不符合删除条件,请确认工程状态后再操作!', |
| | | } |
| | | |
| | | ]; |
| | | |
| | | //定义切换模拟计算弹窗 |
| | | const emit = defineEmits(['switch-dialog']); |
| | | |
| | | onMounted(async () => { |
| | | getProject(); |
| | | }) |
| | | |
| | | // 定义数据返回结果,使用ref创建响应式数据,初始化为空数组 |
| | | let produceList = ref([]) |
| | | |
| | | const getProject = ()=>{ |
| | | request.post(`/glassOptimize/getProjectList`).then((res) => { |
| | | if(res.code==200){ |
| | | produceList.value = deepClone(res.data.data); |
| | | xGrid.value.loadData(produceList.value) |
| | | }else{ |
| | | ElMessage.warning(res.msg) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const gridEvents = { |
| | | menuClick({menu, row}) { |
| | | const $grid = xGrid.value; |
| | | if ($grid) { |
| | | const config = operationConfigs.find(c => c.code === menu.code); |
| | | if (config) { |
| | | if (config.requiresRow && !row) { |
| | | ElMessage.warning('未选中工程,请选中工程后再进行当前操作!'); |
| | | return; |
| | | } |
| | | if (config.code === 'compute') { |
| | | config.actionFunction({row}); |
| | | return; |
| | | } |
| | | // 添加确认提示弹窗,询问用户是否进行当前操作 |
| | | ElMessageBox.confirm('是否进行当前操作?', '确认操作', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | if (config.code === 'delProject') { |
| | | if (!row) { |
| | | ElMessage.warning(config.checkMessage); |
| | | return; |
| | | } |
| | | const isInitialStateMatched = config.initialState.includes(String(row.state)); |
| | | if (!isInitialStateMatched) { |
| | | ElMessage.warning(config.checkMessage); |
| | | return; |
| | | } |
| | | deleteProject(row.projectNumber, config); |
| | | } |
| | | }).catch(() => { |
| | | // 用户点击取消后执行的逻辑 |
| | | ElMessage.info('已取消操作'); |
| | | }); |
| | | } else { |
| | | console.error(`未找到操作选项 ${menu.code} 对应的配置,请检查配置项`); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | |
| | | function deleteProject(projectNumber, config) { |
| | | request.post(`/glassOptimize/deleteProject/${projectNumber}`, { |
| | | headers: { |
| | | 'Content-Type': 'application/json' |
| | | } |
| | | }).then((res) => { |
| | | if (res.code==200 && res.data===true) { |
| | | ElMessage.success(config.successMsg); |
| | | // 从列表中移除已删除的工程数据 |
| | | const index = produceList.value.findIndex(item => item.projectNumber === projectNumber); |
| | | if (index !== -1) { |
| | | produceList.value.splice(index, 1); |
| | | xGrid.value.reloadData(produceList.value); |
| | | } |
| | | //刷新工程号 |
| | | processCardRef.value.getProjectId(); |
| | | processCardRef.value.selectFlowCardList(); |
| | | processCardRef.value.selectGlassType(); |
| | | } else { |
| | | console.log('res.code 的值:', res.code, ', 类型:', typeof res.code); |
| | | console.log('res.msg 的值:', res.msg, ', 类型:', typeof res.msg); |
| | | const errorMsg = res.data ? res.data.errorMessage : config.failureMsg; |
| | | ElMessage.error(`操作失败,原因: ${errorMsg}`); |
| | | } |
| | | }).catch((error) => { |
| | | console.error('请求出错,工程删除未完成,详细错误信息:', error); |
| | | ElMessage.error(`请求出错,工程删除未完成,原因: ${errorMsg}`); |
| | | }); |
| | | } |
| | | |
| | | </script> |
| | | |
| | |
| | | <div style="width: 100%; height: 100%;"> |
| | | |
| | | <div id="processCard"> |
| | | <process-card :process-id="projectRow.processId===null?null:projectRow.processId" |
| | | <process-card ref="processCardRef" :process-id="projectRow.processId===null?null:projectRow.processId" |
| | | :technology-number="projectRow.technologyNumber===null?null:projectRow.technologyNumber" |
| | | @updateProcessId="handleProcessIdUpdate" |
| | | @updateTechnologyNumber="handleTechnologyNumberUpdate" |
| | | @updateState="updateState" |
| | | /> |
| | | </div> |
| | | |
| | |
| | | </div> |
| | | |
| | | <div id="project-list"> |
| | | <project-list/> |
| | | <div style="width: 100%;height: 100%"> |
| | | <h1>工程列表</h1> |
| | | <vxe-grid |
| | | size="small" |
| | | @filter-change="filterChanged" |
| | | height="100%" |
| | | class="mytable-scrollbar" |
| | | ref="xGrid" |
| | | v-bind="gridOptions" |
| | | v-on="gridEvents" |
| | | > |
| | | |
| | | <template #num2_filter="{ column, $panel }"> |
| | | <div> |
| | | <div v-for="(option, index) in column.filters" :key="index"> |
| | | <vxe-select v-model="option.data" :placeholder="$t('processCard.pleaseSelect')" @change="changeFilterEvent($event, option, $panel)"> |
| | | <vxe-option value="0" :label="$t('basicData.unchecked')"></vxe-option> |
| | | <vxe-option value="1" :label="$t('basicData.selected')"></vxe-option> |
| | | </vxe-select> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <template #num1_filter="{ column, $panel }"> |
| | | <div> |
| | | <div v-for="(option, index) in column.filters" :key="index"> |
| | | <input |
| | | |
| | | type="type" |
| | | v-model="option.data" |
| | | @keyup.enter.native="$panel.confirmFilter()" |
| | | @input="changeFilterEvent($event, option, $panel)"/> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </vxe-grid> |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | |
| | | </div> |
| | | </template> |
| | |
| | | }, |
| | | |
| | | columns: [ |
| | | {type: 'expand', fixed: "left", slots: {content: 'content'}, width: 50}, |
| | | {type: 'seq', title: t('basicData.Number'), width: 80}, |
| | | {field: 'projectNumber', width: 100, title: '工程号', filters: [{data: ''}], slots: {filter: 'num1_filter'},}, |
| | | {field: 'projectName', width: 50, title: '名称',}, |
| | | {field: 'glassType', width: 50, title: '膜系',}, |
| | |
| | | checkMessage: '当前工程状态不符合模拟计算条件,请确认工程状态后再操作!', |
| | | requiresRow: true, |
| | | actionFunction: async ({row}) => { |
| | | const projectNumber = row.projectNumber; |
| | | emit('switch-dialog', projectNumber); |
| | | const projectNo = row.projectNumber; |
| | | emit('switch-dialog', row); |
| | | } |
| | | }, |
| | | { |
| | |
| | | }, |
| | | { |
| | | code: 'InitializeProject', |
| | | initialState: ['2', '10', '20'], |
| | | initialState: '2', |
| | | targetState: 1, |
| | | successMsg: '初始化工程成功!', |
| | | checkMessage: '当前工程状态不符合初始化条件,请确认工程状态后再操作!', |
| | |
| | | ElMessage.success(config.successMsg); |
| | | return; |
| | | } |
| | | if (config.code === 'compute') { |
| | | config.actionFunction({row}); |
| | | return; |
| | | } |
| | | // 添加确认提示弹窗,询问用户是否进行当前操作 |
| | | ElMessageBox.confirm('是否进行当前操作?', '确认操作', { |
| | | confirmButtonText: '确定', |
| | |
| | | } |
| | | else { |
| | | row.state = config.targetState; |
| | | let code=0 |
| | | const index = produceList.value.findIndex(item => item === row); |
| | | if (index !== -1) { |
| | | produceList.value.splice(index, 1, {...row}); |
| | | xGrid.value.reloadData(produceList.value); |
| | | } |
| | | updateProjectStateAndHandleResponse(row, row.projectNumber, config.targetState, config.successMsg); |
| | | if(config.code === 'undoCompute'){ |
| | | code=1 |
| | | }else if(config.code === 'undoOptimize'){ |
| | | code=2 |
| | | } |
| | | else if(config.code === 'production'){ |
| | | code=3 |
| | | } |
| | | else if(config.code === 'novisible'){ |
| | | code=4 |
| | | } |
| | | else if(config.code === 'InitializeProject'){ |
| | | code=5 |
| | | } |
| | | updateProjectStateAndHandleResponse(row, row.projectNumber, config.targetState,code, config.successMsg); |
| | | } |
| | | } |
| | | }).catch(() => { |
| | |
| | | } |
| | | } |
| | | |
| | | function updateProjectStateAndHandleResponse(row, projectNumber, targetState, successMsg) { |
| | | function updateProjectStateAndHandleResponse(row, projectNumber, targetState,code, successMsg) { |
| | | const updateParams = { |
| | | projectNumber: projectNumber, |
| | | stateToUpdate: targetState |
| | | }; |
| | | request.post(`/glassOptimize/updateProjectState/${projectNumber}/${targetState}`, updateParams, { |
| | | request.post(`/glassOptimize/updateProjectState/${projectNumber}/${targetState}/${code}`, updateParams, { |
| | | headers: { |
| | | 'Content-Type': 'application/json' |
| | | } |
| | |
| | | 'Content-Type': 'application/json' |
| | | } |
| | | }).then((res) => { |
| | | if (Number(res.code) === 200 && (res.msg === "" || res.msg === null)) { |
| | | if (res.code==200 && res.data===true) { |
| | | ElMessage.success(config.successMsg); |
| | | // 从列表中移除已删除的工程数据 |
| | | const index = produceList.value.findIndex(item => item.projectNumber === projectNumber); |
| | |
| | | <script setup> |
| | | import {reactive, ref, watch} from "vue"; |
| | | import {onMounted, reactive, ref, watch} from "vue"; |
| | | import {useI18n} from "vue-i18n"; |
| | | import {Platform, Search, SuccessFilled} from "@element-plus/icons-vue"; |
| | | import useUserInfoStore from "@/stores/userInfo"; |
| | |
| | | //获取工程号 |
| | | const props = defineProps({ |
| | | projectNo : String, |
| | | project: null, |
| | | data: { |
| | | type: Array, |
| | | default: () => [] |
| | | } |
| | | }); |
| | | // 定义响应式数据,用于绑定工程号输入框的值 |
| | | const inputValue = ref(props.projectNo); |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | // 定义混排等级 |
| | | const optionVal = ref('') |
| | | const optionVal = ref(50) |
| | | |
| | | // 定义装载率 |
| | | const percentage1 = ref(80) |
| | |
| | | const heatingTime = ref('') // 加热时间 |
| | | const spacingLong = ref('') // 长轴间隔 |
| | | const spacingWidth = ref('') // 宽轴间隔 |
| | | const quantity = ref('') // 工程片数 |
| | | |
| | | // 定义响应式数据,用于绑定工程号输入框的值 |
| | | let inputValue=ref(null) |
| | | if(props.project!==undefined){ |
| | | inputValue= ref(props.project.projectNumber); |
| | | quantity.value=props.project.quantity |
| | | } |
| | | |
| | | |
| | | const gridOptions = reactive({ |
| | |
| | | ],//表头参数 |
| | | data: null,//表格数据 |
| | | toolbarConfig: { |
| | | buttons: [], |
| | | slots: { |
| | | buttons: "toolbar_buttons" |
| | | }, |
| | | |
| | | }, |
| | | }) |
| | | |
| | | onMounted(async() => { |
| | | await firstLoading() |
| | | }) |
| | | |
| | | const firstLoading = async() => { |
| | | request.post(`/glassOptimize/getConfiguration/钢化`).then((res) => { |
| | | if (res.code == "200") { |
| | | const rawData = res.data.data; |
| | | if (Array.isArray(rawData) && rawData.length > 0) { |
| | | const formattedData = rawData.map(item => { |
| | | const formattedItem = {}; |
| | | for (const key in item) { |
| | | if (typeof item[key] === 'string') { |
| | | //去除字符串属性值开头和结尾的双引号 |
| | | formattedItem[key] = item[key].replace(/^\"|\"$/g, ''); |
| | | } else { |
| | | formattedItem[key] = item[key]; |
| | | } |
| | | } |
| | | return formattedItem; |
| | | }); |
| | | furnaceWidth.value=formattedData[0].load_width |
| | | furnaceLength.value=formattedData[0].load_length |
| | | spacingLong.value=formattedData[0].x_space |
| | | spacingWidth.value=formattedData[0].y_space |
| | | heatingTime.value=formattedData[0].tempering_time |
| | | |
| | | } |
| | | } else { |
| | | ElMessage.warning(res.msg) |
| | | } |
| | | }) |
| | | |
| | | } |
| | | |
| | | // 监听父组件传递的数据变化 |
| | | watch(() => props.data, (newValue) => { |
| | |
| | | } |
| | | }) |
| | | |
| | | |
| | | const options = [ |
| | | { |
| | | value: '0', |
| | | label: '不混排', |
| | | }, |
| | | { |
| | | value: '1', |
| | | label: '轻度混排', |
| | | }, |
| | | { |
| | | value: '2', |
| | | label: '中度混排', |
| | | }, |
| | | { |
| | | value: '3', |
| | | label: '高度混排', |
| | | }, |
| | | ] |
| | | |
| | | |
| | | |
| | |
| | | <template> |
| | | <div style="width: 100%;height: 100%"> |
| | | <!--模拟计算表头--> |
| | | <div id="title" style="margin-top: -10px"> |
| | | <span> |
| | | <div id="title" style="margin-top: -10px;height: 50%"> |
| | | <div style="display: flex"> |
| | | <div style="width: 850px"> |
| | | 工程编号 |
| | | <el-input style="width:150px;margin-left: 30px" clearable v-model="inputValue" placeholder="请输入工程号"></el-input> |
| | | <el-button |
| | |
| | | @click="handleSearchClick" |
| | | >{{ $t('basicData.search') }} |
| | | </el-button> |
| | | </span> |
| | | <span style="float: right ; margin-right: 120px"> |
| | | 工程混排等级 |
| | | <el-select |
| | | placeholder="选择混排等级" |
| | | style="margin-left:10px; width: 200px; " |
| | | ref="getSelect" |
| | | </div> |
| | | <div style="display: flex ; width: 700px;align-items: center;"> |
| | | <span>工程混排等级</span> |
| | | <el-slider |
| | | style="max-width: 200px; flex: 1; margin-left: 10px" |
| | | v-model="optionVal" |
| | | clearable |
| | | class="m-2" |
| | | @change="getWorkOrder" |
| | | > |
| | | <el-option |
| | | v-for="item in options" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | :min="0" |
| | | :max="100" |
| | | :step="1"/> |
| | | <span style="margin-left: 20px ; width: 35px;">{{ optionVal }}%</span> |
| | | |
| | | <el-button type="primary" style="margin-left: 10px" :icon="Platform" @click="handleSimulationClick">模拟计算</el-button> |
| | | <el-button type="primary" style="margin-left: 20px" :icon="SuccessFilled" @click="handleSave">保存</el-button> |
| | | </span><br> |
| | | </div> |
| | | </div><br> |
| | | <div class="demo-progress" style="margin-top: 5px"> |
| | | <div style="display: flex; align-items: center"> |
| | | <span>钢化最大装载</span> |
| | |
| | | :min="0" |
| | | :max="100" |
| | | :step="1"/> |
| | | <span style="margin-left: 20px ; width: 30px;">{{ percentage1 }}%</span> |
| | | <span style="margin-left: 20px ; width: 35px;">{{ percentage1 }}%</span> |
| | | <span style="float: right ; margin-left: 150px;"> |
| | | 工程片数 <vxe-input size="small" disabled class="input" v-model="quantity"></vxe-input> |
| | | 宽轴间隔 <vxe-input size="small" class="input" clearable v-model="spacingWidth"></vxe-input> |
| | | 炉宽(mm) <vxe-input size="small" class="input" clearable v-model="furnaceWidth"></vxe-input> |
| | | </span> |
| | |
| | | :min="0" |
| | | :max="100" |
| | | :step="1"/> |
| | | <span style="margin-left: 20px ; width: 30px;">{{ percentage2 }}%</span> |
| | | <span style="margin-left: 20px ; width: 35px;">{{ percentage2 }}%</span> |
| | | <span style="float: right ; margin-left: 150px;"> |
| | | 加热时间(秒)<vxe-input size="small" class="input" clearable v-model="heatingTime"></vxe-input> |
| | | 长轴间隔 <vxe-input size="small" class="input" clearable v-model="spacingLong"></vxe-input> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div style="height: 50%"> |
| | | <vxe-grid |
| | | size="small" |
| | | @filter-change="filterChanged" |
| | | height="100%" |
| | | height="50%" |
| | | class="mytable-scrollbar" |
| | | ref="xGrid" |
| | | v-bind="gridOptions" |
| | |
| | | </template> |
| | | </vxe-grid> |
| | | </div> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <style scoped> |
| | |
| | | }, |
| | | |
| | | columns:[ |
| | | {type:'seq',fixed:"left",slots: { content:'content' },width: 50}, |
| | | {type: 'seq', title: t('basicData.Number'), width: 80}, |
| | | {field: 'check', title: '选择', width: 250, cellRender: checkboxCellRender }, |
| | | {field: 'process_id',width: 150, title: t('processCard.processId'), sortable: true}, |
| | | {field: 'technology_number',width: 70, title: '层', sortable: true}, |
| | |
| | | |
| | | toolbarConfig: { |
| | | buttons: [], |
| | | slots:{ |
| | | buttons: "toolbar_buttons" |
| | | }, |
| | | zoom: true, |
| | | custom: true |
| | | }, |
| | |
| | | <span>流程卡</span> |
| | | <vxe-grid |
| | | size="small" |
| | | @filter-change="filterChanged" |
| | | height="100%" |
| | | class="mytable-scrollbar" |
| | | ref="xGrid" |
| | |
| | | data:null,//表格数据 |
| | | toolbarConfig: { |
| | | buttons: [], |
| | | slots:{ |
| | | buttons: "toolbar_buttons" |
| | | }, |
| | | zoom: true, |
| | | custom: true |
| | | }, |
| | |
| | | @mousemove="handleRectDragging"
|
| | | @mouseup="handleRectDragEnd"
|
| | | @mouseleave="handleRectDragEnd"
|
| | | @click="handleRectClick(layoutIndex, rectIndex)"
|
| | | >
|
| | | <div class="rect-content">
|
| | | <div class="size">{{ rect.w }}×{{ rect.h }}</div>
|
| | |
| | | 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 },
|
| | |
| | | const dragging = ref(false);
|
| | | const dragStartPos = ref({ x: 0, y: 0 });
|
| | | const dragRect = ref(null);
|
| | | const showJiaHao = ref(false); // 新增:控制jia-hao的显示状态
|
| | | const showJiaHao = ref(false);
|
| | | const showProcessId= ref(false);
|
| | | const themeColor=ref(null)
|
| | | // 提交布局数据到后端
|
| | | const themeColor = ref(null);
|
| | |
|
| | | const submitLayouts = async () => {
|
| | | layouts.value.forEach(layout => {
|
| | | layout.rects.forEach(rect => {
|
| | |
| | | });
|
| | | };
|
| | |
|
| | |
|
| | | //获取优化设置
|
| | | const fetchSettings = async (username) => {
|
| | | try {
|
| | | const response = await request.post(`/glassOptimize/selectOptimizeParms/${username}`);
|
| | |
| | | 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 ) {
|
| | | themeColor.value = parsedData.display.themeColor;
|
| | | |
| | | }
|
| | | |
| | | |
| | | |
| | | console.log( parsedData);
|
| | | } else {
|
| | | console.error('请求失败,状态码:', response.code);
|
| | | }
|
| | |
| | | console.error('请求发生错误:', error);
|
| | | }
|
| | | };
|
| | |
|
| | |
|
| | |
|
| | | const showAddDialog = (layoutIndex, rectIndex) => {
|
| | | ElMessageBox.prompt('请输入成品的宽度和高度', '添加成品', {
|
| | |
| | | w: values[0],
|
| | | h: values[1],
|
| | | isRemain: false
|
| | | |
| | | };
|
| | | addNewRect(layoutIndex, newRect);
|
| | | })
|
| | |
| | |
|
| | | const addNewRect = (layoutIndex, newRect) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const bestFitPosition = findBestFitPosition(layoutIndex, newRect);
|
| | | if (bestFitPosition) {
|
| | | newRect.x = bestFitPosition.x;
|
| | | newRect.y = bestFitPosition.y;
|
| | | layout.rects.push(newRect);
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | ElMessage.warning('无法放置,没有足够的空间');
|
| | | }
|
| | | };
|
| | |
|
| | | const findBestFitPosition = (layoutIndex, newRect) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const obstacles = layout.rects.filter(r => !r.isRemain);
|
| | | let bestFit = null;
|
| | | let minAreaDifference = Infinity;
|
| | |
|
| | | const remainingAreas = calculateRemainingAreas(layout.width, layout.height, obstacles);
|
| | | remainingAreas.forEach(area => {
|
| | | if (newRect.w <= area.w && newRect.h <= area.h) {
|
| | | const areaDifference = Math.abs(area.w * area.h - newRect.w * newRect.h);
|
| | | if (areaDifference < minAreaDifference) {
|
| | | minAreaDifference = areaDifference;
|
| | | bestFit = {
|
| | | x: area.x,
|
| | | y: area.y,
|
| | | w: newRect.w,
|
| | | h: newRect.h
|
| | | };
|
| | | }
|
| | | }
|
| | | });
|
| | |
|
| | | return bestFit;
|
| | | };
|
| | |
|
| | | const layoutContainerStyle = (layoutIndex) => {
|
| | | const containerWidth = (props.gw - 210) / 2;
|
| | | const containerHeight = (props.gh - 100) / 3;
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const scale = Math.min(
|
| | | (props.gw - 100) / layout.width,
|
| | |
| | | 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);
|
| | | };
|
| | |
| | | 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;
|
| | |
|
| | |
| | | }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (newRect.x < 0 || newRect.y < 0 ||
|
| | | newRect.x + newRect.w > layout.width ||
|
| | | newRect.y + newRect.h > layout.height) {
|
| | |
| | | (props.gh - 100) / layout.height
|
| | | );
|
| | |
|
| | | // 拖动结束后自动对齐到最近的整数位置
|
| | | rect.x = Math.round(rect.x);
|
| | | rect.y = Math.round(rect.y);
|
| | |
|
| | | // 只调整位置对齐,不调整大小
|
| | | adjustAlignmentPosition(layoutIndex, rectIndex);
|
| | |
|
| | | // 调整灰色矩形
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | }
|
| | |
|
| | |
| | | const threshold = Math.max(rect.w, rect.h) * 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((rect.x + rect.w) - (otherRect.x + otherRect.w)) < threshold) {
|
| | | // 不调整宽度
|
| | | rect.x = Math.round((otherRect.x + otherRect.w - rect.w));
|
| | | }
|
| | | // 垂直对齐
|
| | | if (Math.abs(rect.y - otherRect.y) < threshold) {
|
| | | rect.y = Math.round((rect.y + otherRect.y) / 2);
|
| | | }
|
| | | // 垂直对齐下边缘
|
| | | if (Math.abs((rect.y + rect.h) - (otherRect.y + otherRect.h)) < threshold) {
|
| | | // 不调整高度
|
| | | rect.y = Math.round((otherRect.y + otherRect.h - rect.h));
|
| | | }
|
| | | });
|
| | |
|
| | | // 确保矩形不会超出布局边界
|
| | | rect.x = Math.max(0, rect.x);
|
| | | rect.y = Math.max(0, rect.y);
|
| | | rect.x = Math.min(rect.x, layout.width - rect.w);
|
| | | rect.y = Math.min(rect.y, layout.height - rect.h);
|
| | |
|
| | | // 调整后重新计算灰色余料
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | };
|
| | |
|
| | | const mergeAdjacentGrayRects = (rects) => {
|
| | |
| | | const rect = layout.rects[rectIndex];
|
| | | const originalState = { ...rect };
|
| | |
|
| | | // 旋转矩形
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | |
|
| | | // 检查旋转后是否与其他蓝色矩形重叠
|
| | | const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
|
| | | let isValidRotation = true;
|
| | |
|
| | |
| | | }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (rect.x + rect.w > layout.width || rect.y + rect.h > layout.height) {
|
| | | isValidRotation = false;
|
| | | }
|
| | |
| | | if (isValidRotation) {
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | // 恢复原状
|
| | | rect.w = originalState.w;
|
| | | rect.h = originalState.h;
|
| | | ElMessage.warning('无法旋转,存在重叠或超出边界');
|
| | |
| | | const rect = layout.rects[rectIndex];
|
| | | const grayRects = layout.rects.filter(r => r.isRemain);
|
| | |
|
| | | // 旋转矩形
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | |
|
| | | // 检查旋转后的矩形是否可以放置在某个灰色矩形的位置
|
| | | const canPlace = grayRects.some(grayRect => {
|
| | | return grayRect.w >= rect.w && grayRect.h >= rect.h;
|
| | | });
|
| | |
|
| | | if (!canPlace) {
|
| | | // 如果不能放置,恢复原状
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | |
| | | return;
|
| | | }
|
| | |
|
| | | // 调整灰色矩形
|
| | | adjustGrayRectangles(layoutIndex);
|
| | |
|
| | | // 移动矩形
|
| | | moveRect(layoutIndex, rectIndex, direction);
|
| | | };
|
| | |
|
| | |
| | | const rect = layout.rects[rectIndex];
|
| | | const originalState = { ...rect };
|
| | |
|
| | | // 计算剩余空间
|
| | | const remainingAreas = calculateRemainingAreas(layout.width, layout.height, layout.rects.filter(r => !r.isRemain));
|
| | | |
| | | // 根据方向计算可移动的最大步长
|
| | | let maxStep = 0;
|
| | | const obstacles = layout.rects.filter(r => r.isRemain || r !== rect);
|
| | |
|
| | | switch (direction) {
|
| | | case 'up':
|
| | | maxStep = rect.y;
|
| | | maxStep = getAvailableSpaceUp(rect, layout, obstacles);
|
| | | break;
|
| | | case 'down':
|
| | | maxStep = layout.height - (rect.y + rect.h);
|
| | | maxStep = getAvailableSpaceDown(rect, layout, obstacles);
|
| | | break;
|
| | | case 'left':
|
| | | maxStep = rect.x;
|
| | | maxStep = getAvailableSpaceLeft(rect, layout, obstacles);
|
| | | break;
|
| | | case 'right':
|
| | | maxStep = layout.width - (rect.x + rect.w);
|
| | | maxStep = getAvailableSpaceRight(rect, layout, obstacles);
|
| | | break;
|
| | | }
|
| | |
|
| | | // 移动步长,根据剩余空间动态调整
|
| | | const stepSize = maxStep;
|
| | | const actualStep = Math.min(maxStep, stepSize);
|
| | | if (maxStep <= 0) {
|
| | | ElMessage.warning('无法移动,没有足够的空间');
|
| | | return;
|
| | | }
|
| | |
|
| | | // 移动矩形
|
| | | switch (direction) {
|
| | | case 'up':
|
| | | rect.y -= actualStep;
|
| | | rect.y -= maxStep;
|
| | | break;
|
| | | case 'down':
|
| | | rect.y += actualStep;
|
| | | rect.y += maxStep;
|
| | | break;
|
| | | case 'left':
|
| | | rect.x -= actualStep;
|
| | | rect.x -= maxStep;
|
| | | break;
|
| | | case 'right':
|
| | | rect.x +=actualStep;
|
| | | rect.x += maxStep;
|
| | | break;
|
| | | }
|
| | |
|
| | | // 检查是否与其他蓝色矩形重叠
|
| | | const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
|
| | | let isValidMove = true;
|
| | |
|
| | |
| | | }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (rect.x < 0 || rect.y < 0 ||
|
| | | rect.x + rect.w > layout.width ||
|
| | | rect.y + rect.h > layout.height) {
|
| | |
| | | if (isValidMove) {
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | // 恢复原状
|
| | | rect.x = originalState.x;
|
| | | rect.y = originalState.y;
|
| | | ElMessage.warning('无法移动,存在重叠或超出边界');
|
| | |
| | | layouts.value = props.layoutData.Layouts;
|
| | | };
|
| | |
|
| | | const getAvailableSpaceUp = (rect, layout, obstacles) => {
|
| | | let maxSpace = rect.y;
|
| | | obstacles.forEach(obstacle => {
|
| | | if (obstacle.y + obstacle.h < rect.y &&
|
| | | obstacle.x <= rect.x + rect.w &&
|
| | | obstacle.x + obstacle.w >= rect.x) {
|
| | | maxSpace = Math.min(maxSpace, rect.y - (obstacle.y + obstacle.h));
|
| | | }
|
| | | });
|
| | | return maxSpace;
|
| | | };
|
| | |
|
| | | let clickEventListener = null;
|
| | | const getAvailableSpaceDown = (rect, layout, obstacles) => {
|
| | | let maxSpace = layout.height - (rect.y + rect.h);
|
| | | obstacles.forEach(obstacle => {
|
| | | if (obstacle.y > rect.y + rect.h &&
|
| | | obstacle.x <= rect.x + rect.w &&
|
| | | obstacle.x + obstacle.w >= rect.x) {
|
| | | maxSpace = Math.min(maxSpace, obstacle.y - (rect.y + rect.h));
|
| | | }
|
| | | });
|
| | | return maxSpace;
|
| | | };
|
| | |
|
| | | const getAvailableSpaceLeft = (rect, layout, obstacles) => {
|
| | | let maxSpace = rect.x;
|
| | | obstacles.forEach(obstacle => {
|
| | | if (obstacle.x + obstacle.w < rect.x &&
|
| | | obstacle.y <= rect.y + rect.h &&
|
| | | obstacle.y + obstacle.h >= rect.y) {
|
| | | maxSpace = Math.min(maxSpace, rect.x - (obstacle.x + obstacle.w));
|
| | | }
|
| | | });
|
| | | return maxSpace;
|
| | | };
|
| | |
|
| | | const getAvailableSpaceRight = (rect, layout, obstacles) => {
|
| | | let maxSpace = layout.width - (rect.x + rect.w);
|
| | | obstacles.forEach(obstacle => {
|
| | | if (obstacle.x > rect.x + rect.w &&
|
| | | obstacle.y <= rect.y + rect.h &&
|
| | | obstacle.y + obstacle.h >= rect.y) {
|
| | | maxSpace = Math.min(maxSpace, obstacle.x - (rect.x + rect.w));
|
| | | }
|
| | | });
|
| | | return maxSpace;
|
| | | };
|
| | |
|
| | | let moveInterval = null;
|
| | |
|
| | | const handleKeyDown = (event) => {
|
| | | if (!focusIndex.value) return;
|
| | |
|
| | | const { layoutIndex, rectIndex } = focusIndex.value;
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | const obstacles = layout.rects.filter(r => r.isRemain || r !== rect);
|
| | |
|
| | | switch (event.key) {
|
| | | case 'ArrowUp':
|
| | | event.preventDefault();
|
| | | if (!moveInterval) {
|
| | | moveInterval = setInterval(() => {
|
| | | moveRect(layoutIndex, rectIndex, 'up');
|
| | | }, 50);
|
| | | }
|
| | | break;
|
| | | case 'ArrowDown':
|
| | | event.preventDefault();
|
| | | if (!moveInterval) {
|
| | | moveInterval = setInterval(() => {
|
| | | moveRect(layoutIndex, rectIndex, 'down');
|
| | | }, 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;
|
| | | }
|
| | | }
|
| | | };
|
| | |
|
| | | 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;
|
| | |
|
| | | // 添加全局点击事件监听器
|
| | | 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) {
|
| | | document.removeEventListener('click', clickEventListener);
|
| | | clickEventListener = null;
|
| | | }
|
| | | document.removeEventListener('keydown', handleKeyDown);
|
| | | document.removeEventListener('keyup', handleKeyUp);
|
| | | });
|
| | | </script>
|
| | |
|
| | |
| | | }
|
| | |
|
| | | .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;
|
| | | .jia-hao, .liuchengka {
|
| | | font-size: 14px;
|
| | | font-weight: bold;
|
| | | white-space: normal;
|
| | | word-wrap: break-word;
|
| | | }
|
| | |
|
| | | .sidebar-item {
|
| | |
| | | emit('updateTechnologyNumber', rowClickIndex.value.technology_number); |
| | | } |
| | | } |
| | | const emit = defineEmits(['updateProcessId', 'updateTechnologyNumber']); |
| | | const emit = defineEmits(['updateProcessId', 'updateTechnologyNumber', 'updateState']); |
| | | |
| | | |
| | | //小圆点单选框 |
| | | let radio = ref(1); |
| | | |
| | | const selectFlowCardList = () => { |
| | | const selectFlowCardList = async () => { |
| | | request.post(`/glassOptimize/getFlowCardList/${optionVal.value}/${radio.value}`).then((res) => { |
| | | if (res.code == 200) { |
| | | xGrid.value.loadData(res.data.data) |
| | |
| | | } |
| | | request.post(`/glassOptimize/addProject/${optionVal.value}/${oddNumbers.value}/${inputProject}`, projectData.value).then((res) => { |
| | | if (res.code == 200 && res.data === true) { |
| | | emit('updateState', 1); |
| | | ElMessage.success(t('basicData.msg.saveSuccess')) |
| | | selectFlowCardList() |
| | | getProjectId(); |
| | | } else { |
| | | ElMessage.warning(res.msg) |
| | | } |
| | |
| | | |
| | | } |
| | | } |
| | | |
| | | //抛出方法到父界面 |
| | | defineExpose({getProjectId,selectFlowCardList,selectGlassType}) |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | <script setup> |
| | | import {onMounted, reactive, ref} from "vue"; |
| | | import {nextTick, onMounted, reactive, ref, watch} from "vue"; |
| | | import {useI18n} from "vue-i18n"; |
| | | import request from "@/utils/request"; |
| | | import {ElMessage} from "element-plus"; |
| | | import {hiprint} from "vue-plugin-hiprint"; |
| | | import {ElMessage, ElMessageBox} from "element-plus"; |
| | | import {defineEmits} from 'vue'; |
| | | const { t } = useI18n() |
| | | |
| | | const xGrid = ref() |
| | | |
| | | |
| | | const gridOptions = reactive({ |
| | | height:'100%', |
| | |
| | | showStatus: true |
| | | }, |
| | | columns:[ |
| | | {type:'expand',fixed:"left",slots: { content:'content' },width: 50}, |
| | | {field: 'id',width: 150, title: 'ID',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'project_no',width: 150, title: '工程号',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | | {field: 'project_name',width: 150, title: '项目名称',filters:[{ data: '' }],slots: { filter: 'num1_filter' }, sortable: true}, |
| | |
| | | zoom: true, |
| | | custom: true |
| | | }, |
| | | //右键菜单选项 |
| | | menuConfig: { |
| | | body: { |
| | | options: [ |
| | | [ |
| | | {code: 'openProject', name: '打开工程', prefixIcon: 'vxe-icon-folder-open'}, |
| | | {code: 'compute', name: '模拟计算', prefixIcon: 'vxe-icon-subtable'}, |
| | | {code: 'delProject', name: '删除工程', prefixIcon: 'vxe-icon-delete'}, |
| | | ], |
| | | [] |
| | | ] |
| | | } |
| | | } |
| | | |
| | | }) |
| | | |
| | | // 定义操作配置对象数组,集中管理不同操作选项对应的参数 |
| | | const operationConfigs = [ |
| | | { |
| | | code: 'openProject', // 打开工程 |
| | | initialState: ['10', '20', '100', '200'], // |
| | | targetState: null, |
| | | successMsg: '已打开!', |
| | | checkMessage: '当前工程状态不符合条件,请确认工程状态后再操作!', |
| | | requiresRow: true, |
| | | openFile: async ({row}) => { |
| | | const projectNumber = row.projectNumber; |
| | | const thickness = row.thickness; |
| | | const glassType = row.glassType; |
| | | await router.push({ |
| | | name: 'optimizeInfo', |
| | | params: { |
| | | projectNo: projectNumber, |
| | | thickNess: thickness, |
| | | model: glassType |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | { |
| | | code: 'compute', // 打开模拟计算操作 |
| | | initialState: ['1', '2'], // |
| | | targetState: null, |
| | | successMsg: '模拟计算已启动!', |
| | | checkMessage: '当前工程状态不符合模拟计算条件,请确认工程状态后再操作!', |
| | | requiresRow: true, |
| | | actionFunction: async ({row}) => { |
| | | const projectNo = row.projectNumber; |
| | | emit('switch-dialog', row); |
| | | } |
| | | }, |
| | | { |
| | | code: 'delProject', |
| | | initialState: ['1', '2', '10', '20', '100'], |
| | | targetState: null, |
| | | successMsg: '工程删除成功!', |
| | | checkMessage: '当前工程状态不符合删除条件,请确认工程状态后再操作!', |
| | | } |
| | | |
| | | ]; |
| | | |
| | | //定义切换模拟计算弹窗 |
| | | const emit = defineEmits(['switch-dialog']); |
| | | |
| | | onMounted(async () => { |
| | | getProject(); |
| | | }) |
| | | |
| | | |
| | | |
| | | const getProject = ()=>{ |
| | | request.post(`/glassOptimize/getProjectList`).then((res) => { |
| | |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const gridEvents = { |
| | | menuClick({menu, row}) { |
| | | const $grid = xGrid.value; |
| | | if ($grid) { |
| | | const config = operationConfigs.find(c => c.code === menu.code); |
| | | if (config) { |
| | | if (config.requiresRow && !row) { |
| | | ElMessage.warning('未选中工程,请选中工程后再进行当前操作!'); |
| | | return; |
| | | } |
| | | if (config.code === 'compute') { |
| | | config.actionFunction({row}); |
| | | return; |
| | | } |
| | | // 添加确认提示弹窗,询问用户是否进行当前操作 |
| | | ElMessageBox.confirm('是否进行当前操作?', '确认操作', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | if (config.code === 'viewTempered') { |
| | | ElMessageBox.alert('当前点击的是查看钢化版图功能,目前暂时仅做提示,暂无实际查看操作!', '功能提示', { |
| | | confirmButtonText: '我知道了' |
| | | }); |
| | | return; |
| | | } |
| | | if (config.code === 'viewOptimize') { |
| | | ElMessageBox.alert('当前点击的是查看钢化版图功能,目前暂时仅做提示,暂无实际查看操作!', '功能提示', { |
| | | confirmButtonText: '我知道了' |
| | | }); |
| | | return; |
| | | } |
| | | if (config.code === 'delProject') { |
| | | if (!row) { |
| | | ElMessage.warning(config.checkMessage); |
| | | return; |
| | | } |
| | | const isInitialStateMatched = config.initialState.includes(String(row.state)); |
| | | if (!isInitialStateMatched) { |
| | | ElMessage.warning(config.checkMessage); |
| | | return; |
| | | } |
| | | deleteProject(row.projectNumber, config); |
| | | } else if (!checkOperationCondition(config, row)) { |
| | | ElMessage.warning(config.checkMessage); |
| | | return; |
| | | } else { |
| | | if (config.code === 'openProject') { |
| | | handleSameDataOperation(row).then(({isRoutesEqual}) => { |
| | | if (!isRoutesEqual) { |
| | | config.openFile({row}); |
| | | ElMessage.success(config.successMsg); |
| | | } |
| | | }); |
| | | } else if (config.code === 'compute') { |
| | | config.actionFunction({row}); |
| | | } else if (config.code === 'optimizeTypography') { |
| | | handleSameDataOperation(row).then(({isRoutesEqual}) => { |
| | | if (!isRoutesEqual) { |
| | | config.Typography({row}); |
| | | ElMessage.success(config.successMsg); |
| | | } |
| | | }); |
| | | } |
| | | else { |
| | | row.state = config.targetState; |
| | | const index = produceList.value.findIndex(item => item === row); |
| | | if (index !== -1) { |
| | | produceList.value.splice(index, 1, {...row}); |
| | | xGrid.value.reloadData(produceList.value); |
| | | } |
| | | updateProjectStateAndHandleResponse(row, row.projectNumber, config.targetState, config.successMsg); |
| | | } |
| | | } |
| | | }).catch(() => { |
| | | // 用户点击取消后执行的逻辑 |
| | | ElMessage.info('已取消操作'); |
| | | }); |
| | | } else { |
| | | console.error(`未找到操作选项 ${menu.code} 对应的配置,请检查配置项`); |
| | | } |
| | | } |
| | | }, |
| | | cellDblclick: ({row}) => { |
| | | const menu = {code: 'openProject'}; |
| | | nextTick(() => { |
| | | handleSameDataOperation(row).then(({isRoutesEqual}) => { |
| | | if (!isRoutesEqual) { |
| | | gridEvents.menuClick({menu, row}); |
| | | } |
| | | }); |
| | | }); |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | <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 {
|
| | |
| | | |
| | | pageNum=1 |
| | | produceList = deepClone(res.data.data) |
| | | console.log(res.data.data) |
| | | const orderDetails = res.data.data |
| | | orderDetails.forEach(item => { |
| | | item.otherColumns = JSON.parse(item.otherColumns) |
| | |
| | | |
| | | //修改工程状态 |
| | | @ApiOperation("修改工程状态接口") |
| | | @PostMapping("/updateProjectState/{projectNumber}/{state}") |
| | | @PostMapping("/updateProjectState/{projectNumber}/{state}/{code}") |
| | | public Result updateProjectState( |
| | | @PathVariable String projectNumber, |
| | | @PathVariable Integer state |
| | | @PathVariable Integer state, |
| | | @PathVariable Integer code |
| | | ) { |
| | | if (glassOptimizeService.updateProjectState(projectNumber, state)) { |
| | | if (glassOptimizeService.updateProjectState(projectNumber, state,code)) { |
| | | return Result.seccess(); |
| | | } else { |
| | | throw new ServiceException(Constants.Code_500, "修改失败"); |
| | |
| | | return new ResponseEntity<>(optContent.getBytes(), headers, HttpStatus.OK); |
| | | } |
| | | |
| | | @PostMapping("/getConfiguration/{type}") |
| | | public Result getConfiguration(@PathVariable String type) { |
| | | return Result.seccess(glassOptimizeService.getConfiguration(type)); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | |
| | | package com.example.erp.mapper.pp; |
| | | |
| | | |
| | | import com.example.erp.entity.pp.FlowCard; |
| | | import com.example.erp.entity.pp.OptimizeProjectMange; |
| | | import com.example.erp.entity.sd.OrderGlassDetail; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | |
| | | //工程信息流程卡 |
| | | List<Map<String, Object>> getProcessCardMp(String projectNo); |
| | | |
| | | List<FlowCard> getFlowCardList(String projectNo); |
| | | |
| | | //库存信息 |
| | | List<Map<String, Object>> materialStoreMp(String thickness, String model); |
| | | |
| | |
| | | |
| | | //创建工程膜系查询 |
| | | List<Map<String, Object>> getFlowCardListMp(String optionVal, Integer radio); |
| | | List<Map<String, Object>> getFlowCardListWhole(String optionVal); |
| | | List<Map<String, Object>> getFlowCardListNormal(String optionVal); |
| | | List<Map<String, Object>> getFlowCardListPatch(String optionVal); |
| | | |
| | | //工程管理工程号查询 |
| | | List<OptimizeProjectMange> optimizeProjectMangeMp(Date startSelectTime, Date endSelectTime, OptimizeProjectMange optimizeProjectMange); |
| | |
| | | //删除工程 |
| | | int deleteProjectMp(String projectNumber); |
| | | |
| | | int deleteOptimizeHeatDetail(String projectNumber); |
| | | |
| | | int deleteOptimizeHeatLayout(String projectNumber); |
| | | |
| | | int deleteOptimizeDetail(String projectNumber); |
| | | |
| | | //模拟计算工程号查询 |
| | | List<Map<String, Object>> selectProjectComputeMp(@Param("projectNo")String projectNumber); |
| | | |
| | | Map<String, Object> selectProjectCount(@Param("projectNo")String projectNumber); |
| | | |
| | | //模拟计算流程卡详情 |
| | | List<Map<String, Object>> selectComputeDetailMp(String processId); |
| | |
| | | |
| | | Boolean updateFlowCardProject(String processId, String technologyNumber, String projectId); |
| | | |
| | | Boolean updateFlowCardProjectReturn(String processId, String technologyNumber, String projectId); |
| | | |
| | | Double getSelectArea(String processId, String technologyNumber); |
| | | |
| | | Boolean addProjectMp(String projectId, String projectNmae, String glassThickness, String glassType, Integer sumQuantity, Double sumArea, String userName); |
| | | Boolean addProjectMp(String projectId, String projectNmae, String glassThickness, String glassType, |
| | | Integer sumQuantity, Double sumArea, String userName,Integer processIdCount, String processId, Integer type); |
| | | |
| | | List<Map<String, Object>> getTemperedConfiguration(); |
| | | } |
| | |
| | | Map<String, Object> getSelectotherMoney(@Param("orderId") String orderId,@Param("deliveryId") String deliveryId, |
| | | @Param("orderNumber") Integer orderNumber,@Param("key") String key,@Param("value") Double value); |
| | | |
| | | Map<String, Object> getSelectOrderotherMoney(@Param("orderId") String orderId,@Param("orderNumber") Integer orderNumber, @Param("key") String key,@Param("value") Double value); |
| | | Map<String, Object> getSelectOrderotherMoney(@Param("orderId") String orderId,@Param("orderNumber") Integer orderNumber, @Param("key") String key,@Param("value") Double value,@Param("quantity") Integer quantity); |
| | | |
| | | Map<String, Object> getSelectOrderotherMoneys(@Param("orderId") String orderId,@Param("orderNumber") Integer orderNumber, @Param("key") String key,@Param("value") Double value); |
| | | |
| | | List <Map<String, Object>> getSelectOrderDetailPrinting(@Param("productId") Integer productId,@Param("orderId") String orderId); |
| | | |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.sql.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | |
| | | //工程查询流程卡 |
| | | public Map<String, Object> getFlowCardList(String optionVal, Integer radio) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("data", glassOptimizeMapper.getFlowCardListMp(optionVal, radio)); |
| | | if(radio==1){ |
| | | map.put("data", glassOptimizeMapper.getFlowCardListWhole(optionVal)); |
| | | }else if(radio==2){ |
| | | map.put("data", glassOptimizeMapper.getFlowCardListNormal(optionVal)); |
| | | }else{ |
| | | map.put("data", glassOptimizeMapper.getFlowCardListPatch(optionVal)); |
| | | } |
| | | |
| | | |
| | | return map; |
| | | } |
| | |
| | | } |
| | | |
| | | //修改排版状态 |
| | | public Boolean updateProjectState(String projectNumber, Integer state) { |
| | | public Boolean updateProjectState(String projectNumber, Integer state, Integer code) { |
| | | if (!projectNumber.isEmpty()) { |
| | | //撤销模拟计算 |
| | | if(code==1){ |
| | | glassOptimizeMapper.deleteOptimizeHeatDetail(projectNumber); |
| | | glassOptimizeMapper.deleteOptimizeHeatLayout(projectNumber); |
| | | glassOptimizeMapper.updateProjectStateMp(projectNumber, state); |
| | | } |
| | | //撤销优化排版 |
| | | else if(code==2){ |
| | | glassOptimizeMapper.deleteOptimizeHeatDetail(projectNumber); |
| | | glassOptimizeMapper.deleteOptimizeHeatDetail(projectNumber); |
| | | glassOptimizeMapper.deleteOptimizeHeatLayout(projectNumber); |
| | | glassOptimizeMapper.updateProjectStateMp(projectNumber, state); |
| | | } |
| | | //允许生产 |
| | | else if(code==3){ |
| | | glassOptimizeMapper.updateProjectStateMp(projectNumber, state); |
| | | } |
| | | //生产不可见 |
| | | else if(code==4){ |
| | | glassOptimizeMapper.updateProjectStateMp(projectNumber, state); |
| | | } |
| | | //初始化工程 |
| | | else if(code==5){ |
| | | glassOptimizeMapper.updateProjectStateMp(projectNumber, state); |
| | | } |
| | | return true; |
| | | } else { |
| | | return false; |
| | |
| | | } |
| | | |
| | | //删除工程 |
| | | public Map<String, Object> deleteProject(String projectNumber) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("data", glassOptimizeMapper.deleteProjectMp(projectNumber)); |
| | | return map; |
| | | public boolean deleteProject(String projectNumber) { |
| | | Map<String, Object> stringObjectMap = glassOptimizeMapper.selectProjectCount(projectNumber); |
| | | if(stringObjectMap.get("state").equals(10)){ |
| | | glassOptimizeMapper.deleteOptimizeHeatDetail(projectNumber); |
| | | glassOptimizeMapper.deleteOptimizeHeatLayout(projectNumber); |
| | | }else if(stringObjectMap.get("state").equals(20)){ |
| | | glassOptimizeMapper.deleteOptimizeDetail(projectNumber); |
| | | glassOptimizeMapper.deleteOptimizeHeatDetail(projectNumber); |
| | | glassOptimizeMapper.deleteOptimizeHeatLayout(projectNumber); |
| | | } |
| | | List<FlowCard> flowCardList =glassOptimizeMapper.getFlowCardList(projectNumber); |
| | | for (FlowCard flowCard:flowCardList){ |
| | | glassOptimizeMapper.updateFlowCardProjectReturn(flowCard.getProcessId(),flowCard.getTechnologyNumber(),projectNumber); |
| | | } |
| | | glassOptimizeMapper.deleteProjectMp(projectNumber); |
| | | return true; |
| | | } |
| | | |
| | | |
| | |
| | | public Map<String, Object>selectProjectComputeSv(String projectNumber) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("data", glassOptimizeMapper.selectProjectComputeMp(projectNumber)); |
| | | //map.put("project", glassOptimizeMapper.selectProjectCount(projectNumber)); |
| | | return map; |
| | | } |
| | | |
| | |
| | | if ("null".equals(projectNmae)) { |
| | | projectNmae = ""; |
| | | } |
| | | Double sumArea = (double) 0; |
| | | Double area = (double) 0; |
| | | BigDecimal sumArea = new BigDecimal(0); |
| | | double area = 0; |
| | | Integer sumQuantity = 0; |
| | | Integer type = 1; |
| | | StringBuilder processId= new StringBuilder(); |
| | | List<FlowCard> flowCardList = JSONArray.parseArray(JSONObject.toJSONString(object.get("projectdetail")), FlowCard.class); |
| | | if (!flowCardList.isEmpty()) { |
| | | for (FlowCard flowCard : flowCardList) { |
| | | //给流程卡表添加对应的工程号 |
| | | glassOptimizeMapper.updateFlowCardProject(flowCard.getProcessId(),flowCard.getTechnologyNumber(),projectId); |
| | | area = glassOptimizeMapper.getSelectArea(flowCard.getProcessId(),flowCard.getTechnologyNumber()); |
| | | sumArea += area; |
| | | area = glassOptimizeMapper.getSelectArea(flowCard.getProcessId(),flowCard.getTechnologyNumber()).doubleValue(); |
| | | sumArea = sumArea.add(BigDecimal.valueOf(area)); |
| | | sumQuantity +=flowCard.getQuantity(); |
| | | processId.append(flowCard.getProcessId()).append("-").append(flowCard.getTechnologyNumber()).append(";"); |
| | | } |
| | | int index = optionVal.indexOf("mm"); |
| | | // 获取 "mm" 前面的部分 |
| | | String glass_thickness = optionVal.substring(0, index); |
| | | // 获取 "mm" 后面的部分 |
| | | String glass_type = optionVal.substring(index + 2); |
| | | glassOptimizeMapper.addProjectMp(projectId,projectNmae,glass_thickness,glass_type,sumQuantity,sumArea,userName); |
| | | glassOptimizeMapper.addProjectMp(projectId,projectNmae,glass_thickness,glass_type,sumQuantity,sumArea.doubleValue(),userName, |
| | | flowCardList.size(), String.valueOf(processId),type); |
| | | return true; |
| | | } |
| | | else { |
| | |
| | | |
| | | } |
| | | } |
| | | |
| | | public Map<String, Object> getConfiguration(String type) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | if(type.equals("钢化")){ |
| | | map.put("data", glassOptimizeMapper.getTemperedConfiguration()); |
| | | }else if(type.equals("磨量")){ |
| | | map.put("data", glassOptimizeMapper.getTemperedConfiguration()); |
| | | }else if(type.equals("修边")){ |
| | | map.put("data", glassOptimizeMapper.getTemperedConfiguration()); |
| | | } |
| | | |
| | | return map; |
| | | } |
| | | } |
| | |
| | | if(isnull) { |
| | | Map<String, Object> moneryItemmap = new HashMap<>(); |
| | | Map<String, Object> deliveryDetailOtherMoney = deliveryDetailMapper.getSelectOrderotherMoney(orderDetail.getOrderId(),orderDetail.getOrderNumber(), |
| | | key, Double.valueOf(jsonObject.get(key).toString())); |
| | | key, Double.valueOf(jsonObject.get(key).toString()),orderDetail.getDeliveryDetail().getQuantity()); |
| | | if(deliveryDetailOtherMoney.get("monery")!=null){ |
| | | otherMoneys=otherMoneys+Double.valueOf(deliveryDetailOtherMoney.get("monery").toString()); |
| | | deliveryDetailotherMoneys=Double.valueOf(deliveryDetailOtherMoney.get("monery").toString()); |
| | |
| | | boolean isnull = key.contains("M"); |
| | | if(isnull){ |
| | | Map<String, Object> moneryItemmap = new HashMap<>(); |
| | | Map<String, Object> deliveryDetailOtherMoney = deliveryDetailMapper.getSelectOrderotherMoney(detail.getOrderId(),Integer.parseInt(stringObjectMap.get("order_number").toString()) |
| | | Map<String, Object> deliveryDetailOtherMoney = deliveryDetailMapper.getSelectOrderotherMoneys(detail.getOrderId(),Integer.parseInt(stringObjectMap.get("order_number").toString()) |
| | | ,key,Double.valueOf(jsonObject.get(key).toString())); |
| | | grossAmount=grossAmount.add(BigDecimal.valueOf(Double.parseDouble(deliveryDetailOtherMoney.get("monery").toString()))); |
| | | moneryItemmap.put("DeliveryDetailOtherMoney", deliveryDetailOtherMoney); |
| | |
| | | fc.order_number |
| | | </select> |
| | | |
| | | <select id="getFlowCardList"> |
| | | SELECT * |
| | | FROM |
| | | pp.flow_card AS fc |
| | | WHERE |
| | | fc.project_no = #{projectNo} |
| | | |
| | | </select> |
| | | |
| | | <!--库存信息--> |
| | | <select id="materialStoreMp"> |
| | | SELECT |
| | |
| | | AND pd.glass_sort = fc.technology_number |
| | | WHERE |
| | | CONCAT( JSON_UNQUOTE( JSON_EXTRACT( pd.separation, '$.thickness' )), JSON_UNQUOTE( JSON_EXTRACT( pd.separation, '$.color' )) )= #{optionVal} |
| | | and ISNULL(fc.project_no) |
| | | and ISNULL(fc.project_no) and fc.layout_status=1 |
| | | GROUP BY |
| | | fc.process_id, |
| | | fc.technology_number |
| | | ORDER BY |
| | | fc.process_id, |
| | | fc.technology_number |
| | | </select> |
| | | |
| | | <select id="getFlowCardListWhole"> |
| | | SELECT 流程卡号 as process_id, |
| | | 层 as technology_number, |
| | | 总层数 as TotalFloors, |
| | | 规格 as TotalNumber, |
| | | 数量 as quantity, |
| | | 形状 as shape, |
| | | 项目 as project, |
| | | 单片名称 as glass_child, |
| | | 面积 as area, |
| | | GlassType as glassType |
| | | FROM pp.v_optimize_process_whole where |
| | | CONCAT( JSON_UNQUOTE( JSON_EXTRACT( GlassType, '$.thickness' )), JSON_UNQUOTE( JSON_EXTRACT( GlassType, '$.color' )) )= #{optionVal} |
| | | </select> |
| | | |
| | | <select id="getFlowCardListNormal"> |
| | | SELECT 流程卡号 as process_id, |
| | | 层 as technology_number, |
| | | 总层数 as TotalFloors, |
| | | 规格 as TotalNumber, |
| | | 数量 as quantity, |
| | | 形状 as shape, |
| | | 项目 as project, |
| | | 单片名称 as glass_child, |
| | | 面积 as area, |
| | | GlassType as glassType |
| | | FROM pp.v_optimize_process_normal where |
| | | CONCAT( JSON_UNQUOTE( JSON_EXTRACT( GlassType, '$.thickness' )), JSON_UNQUOTE( JSON_EXTRACT( GlassType, '$.color' )) )= #{optionVal} |
| | | </select> |
| | | |
| | | <select id="getFlowCardListPatch"> |
| | | SELECT 流程卡号 as process_id, |
| | | 层 as technology_number, |
| | | 总层数 as TotalFloors, |
| | | 规格 as TotalNumber, |
| | | 数量 as quantity, |
| | | 形状 as shape, |
| | | 项目 as project, |
| | | 单片名称 as glass_child, |
| | | 面积 as area, |
| | | GlassType as glassType |
| | | FROM pp.v_optimize_process_patch where |
| | | CONCAT( JSON_UNQUOTE( JSON_EXTRACT( GlassType, '$.thickness' )), JSON_UNQUOTE( JSON_EXTRACT( GlassType, '$.color' )) )= #{optionVal} |
| | | </select> |
| | | |
| | | <!--工程管理--> |
| | |
| | | where project_no = #{projectNumber} |
| | | </delete> |
| | | |
| | | <delete id="deleteOptimizeHeatDetail"> |
| | | delete from pp.optimize_heat_detail |
| | | where project_no = #{projectNumber} |
| | | </delete> |
| | | |
| | | <delete id="deleteOptimizeHeatLayout"> |
| | | delete from pp.optimize_heat_layout |
| | | where project_no = #{projectNumber} |
| | | </delete> |
| | | |
| | | <delete id="deleteOptimizeDetail"> |
| | | delete from pp.optimize_detail |
| | | where project_no = #{projectNumber} |
| | | </delete> |
| | | |
| | | <select id="getProjectListMp"> |
| | | SELECT |
| | | p.id, |
| | | p.project_no, |
| | | p.project_no as projectNumber, |
| | | p.project_name, |
| | | p.glass_type, |
| | | p.glass_thickness, |
| | | p.type, |
| | | p.state, |
| | | p.glass_total, |
| | | p.glass_total as quantity, |
| | | p.glass_total_area, |
| | | p.process_qty, |
| | | p.process_cards, |
| | |
| | | fc.process_id, fc.technology_number |
| | | ORDER BY |
| | | fc.process_id, fc.technology_number; |
| | | </select> |
| | | |
| | | <select id="selectProjectCount"> |
| | | select * from pp.optimize_project where project_no=#{projectNo} |
| | | </select> |
| | | |
| | | <!--模拟计算流程卡详情--> |
| | |
| | | </select> |
| | | |
| | | <update id="updateFlowCardProject"> |
| | | UPDATE pp.flow_card set project_no=#{projectId} |
| | | UPDATE pp.flow_card set project_no=#{projectId},layout_status=2 |
| | | where process_id=#{processId} and technology_number=#{technologyNumber} |
| | | </update> |
| | | |
| | | <update id="updateFlowCardProjectReturn"> |
| | | UPDATE pp.flow_card set project_no=null,layout_status=1 |
| | | where process_id=#{processId} and technology_number=#{technologyNumber} |
| | | </update> |
| | | |
| | |
| | | </select> |
| | | |
| | | <insert id="addProjectMp"> |
| | | insert into pp.optimize_project (project_no, project_name, order_glass_type, order_glass_thickness) |
| | | values (#{projectId}, #{projectNmae}, #{glassType}, #{glassThickness}) |
| | | insert into pp.optimize_project (project_no, project_name, order_glass_type, order_glass_thickness,glass_type, glass_thickness, |
| | | glass_total,glass_total_area,type,state,process_qty,process_cards) |
| | | values (#{projectId}, #{projectNmae}, #{glassType}, #{glassThickness}, #{glassType}, #{glassThickness},#{sumQuantity}, #{sumArea}, |
| | | #{type},1,#{processIdCount},#{processId}) |
| | | </insert> |
| | | |
| | | |
| | |
| | | FROM pp.optimize_project_file |
| | | WHERE project_no=#{processId} and type='优化结果'; |
| | | </select> |
| | | |
| | | <select id="getTemperedConfiguration"> |
| | | select JSON_EXTRACT( oc.config_detail, '$.glass_thickness' ) as glass_thickness, |
| | | JSON_EXTRACT( oc.config_detail, '$.glass_type' ) as glass_type, |
| | | JSON_EXTRACT( oc.config_detail, '$.tempering_time' ) as tempering_time, |
| | | JSON_EXTRACT( oc.config_detail, '$.load_width' ) as load_width, |
| | | JSON_EXTRACT( oc.config_detail, '$.load_length' ) as load_length, |
| | | JSON_EXTRACT( oc.config_detail, '$.x_space' ) as x_space, |
| | | JSON_EXTRACT( oc.config_detail, '$.y_space' ) as y_space |
| | | from pp.optimize_admin oa left join pp.optimize_config oc on oa.h_id=oc.id where name='admin' |
| | | </select> |
| | | </mapper> |
| | |
| | | od.shape, |
| | | fgi.actual_signal_area, |
| | | od.area, |
| | | od.gross_area, |
| | | dd.area as gross_area, |
| | | od.compute_area, |
| | | dd.area as compute_gross_area, |
| | | od.processing_note, |
| | |
| | | </select> |
| | | |
| | | <select id="getSelectOrderotherMoney" > |
| | | select bom.alias,ifnull(oom.price,0) as price,#{value}*#{quantity} as count,ifnull(oom.price,0)*#{value}*#{quantity} as monery |
| | | from order_detail od |
| | | left join order_other_money oom on oom.order_id=od.order_id and oom.column=#{key} |
| | | left join basic_other_money bom on bom.`column`=oom.`column` |
| | | where od.order_id = #{orderId} and od.order_number=#{orderNumber} and (od.other_columns!='{}' or od.other_columns!=null) |
| | | </select> |
| | | |
| | | <select id="getSelectOrderotherMoneys" > |
| | | select bom.alias,ifnull(oom.price,0) as price,#{value}*od.quantity as count,ifnull(oom.price,0)*#{value}*od.quantity as monery |
| | | from order_detail od |
| | | left join order_other_money oom on oom.order_id=od.order_id and oom.column=#{key} |