| | |
| | | <script setup> |
| | | import {ref, computed, watch} from "vue"; |
| | | import {Connection} from "@element-plus/icons-vue"; |
| | | import { ElMessage, ElMessageBox } from 'element-plus'; |
| | | import {useRoute, useRouter} from "vue-router"; |
| | | import useOrderInfoStore from "@/stores/sd/order/orderInfo"; |
| | | import requestOptimize from "@/utils/requestOptimize"; |
| | | import request from "@/utils/request"; |
| | | |
| | | const router = useRouter() |
| | | const orderInfo = useOrderInfoStore() |
| | |
| | | const remainingSeconds = seconds.value % 60; |
| | | return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; |
| | | }); |
| | | |
| | | const showCompleteButton = ref(false); |
| | | const startTimer = () => { |
| | | if(progress.value>0){ |
| | | seconds.value = 0; |
| | |
| | | if(props.optimizeData!=null){ |
| | | document.getElementById("start").disabled=true |
| | | document.getElementById("complete").style.display="none" |
| | | showCompleteButton.value = false; |
| | | console.log(props.optimizeData) |
| | | if (!isRunning.value) { |
| | | isRunning.value = true; |
| | | intervalId = setInterval(() => { |
| | | seconds.value++; |
| | | progress.value += 1; |
| | | if (progress.value >= 100) { |
| | | progress.value = 100; |
| | | clearInterval(intervalId); |
| | | // 最大只到99% |
| | | if (progress.value < 99) { |
| | | progress.value += 1; |
| | | } |
| | | }, 1000); |
| | | } |
| | | |
| | | // 发送请求到真实接口 |
| | | requestOptimize.post('/api/optimize', props.optimizeData, {timeout: 300000}) |
| | | .then((response) => { |
| | | // 处理响应数据 |
| | | if (response.code === 200 && response.data) { |
| | | // 解析接口返回的数据 |
| | | const result = response.data; |
| | | |
| | | mockData.value = { |
| | | code: 200, |
| | | data: [{ |
| | | "projectNo":"P25041001", |
| | | "totalQuantity":1, |
| | | "glassTotalQuantity":1, |
| | | "glassTotalArea":1, |
| | | "avgCutRate":1, |
| | | "lastCutRate":1, |
| | | "validCutRate":1, |
| | | "layouts":[ |
| | | { |
| | | "stockId":3, |
| | | "usageRate":0.9, |
| | | "width":4500, |
| | | "height":2440, |
| | | "stockCode":11, |
| | | "upTrim":12, |
| | | "downTrim":12, |
| | | "leftTrim":12, |
| | | "rightTrim":12, |
| | | "quantity":1, |
| | | "glassQuantity":6, |
| | | "glassArea":45, |
| | | "materialType":1, |
| | | "mergeID":1, |
| | | "glassDetails":[ |
| | | {"isRemain":false, |
| | | "width":2070, |
| | | "height":725, |
| | | "realWidth":2070, |
| | | "realHeight":725, |
| | | "layer":1, |
| | | "totalLayer":2, |
| | | "orderSort":1, |
| | | "processId":"NG22091408A06", |
| | | "stockSort":1, |
| | | "polySort":1, |
| | | "markIcon":"", |
| | | "x":0, |
| | | "y":0, |
| | | "patchState":0, |
| | | "isRotate":0, |
| | | "rackNo":1, |
| | | "glassPoint":{} |
| | | }, |
| | | {"isRemain":false, |
| | | "width":2070, |
| | | "height":725, |
| | | "realWidth":2070, |
| | | "realHeight":725, |
| | | "layer":1, |
| | | "totalLayer":2, |
| | | "orderSort":1, |
| | | "processId":"NG22091408A06", |
| | | "stockSort":1, |
| | | "polySort":2, |
| | | "markIcon":"", |
| | | "x":2070, |
| | | "y":0, |
| | | "patchState":0, |
| | | "isRotate":0, |
| | | "rackNo":1, |
| | | "glassPoint":{} |
| | | }, |
| | | {"isRemain":false, |
| | | "width":2070, |
| | | "height":725, |
| | | "realWidth":2070, |
| | | "realHeight":725, |
| | | "layer":1, |
| | | "totalLayer":2, |
| | | "orderSort":1, |
| | | "processId":"NG22091408A06", |
| | | "stockSort":1, |
| | | "polySort":3, |
| | | "markIcon":"", |
| | | "x":0, |
| | | "y":725, |
| | | "patchState":0, |
| | | "isRotate":0, |
| | | "rackNo":1, |
| | | "glassPoint":{} |
| | | }, |
| | | {"isRemain":false, |
| | | "width":2070, |
| | | "height":725, |
| | | "realWidth":2070, |
| | | "realHeight":725, |
| | | "layer":1, |
| | | "totalLayer":2, |
| | | "orderSort":1, |
| | | "processId":"NG22091408A06", |
| | | "stockSort":1, |
| | | "polySort":4, |
| | | "markIcon":"", |
| | | "x":2070, |
| | | "y":725, |
| | | "patchState":0, |
| | | "isRotate":0, |
| | | "rackNo":1, |
| | | "glassPoint":{} |
| | | }, |
| | | {"isRemain":false, |
| | | "width":2070, |
| | | "height":725, |
| | | "realWidth":2070, |
| | | "realHeight":725, |
| | | "layer":1, |
| | | "totalLayer":2, |
| | | "orderSort":1, |
| | | "processId":"NG22091408A06", |
| | | "stockSort":1, |
| | | "polySort":5, |
| | | "markIcon":"", |
| | | "x":0, |
| | | "y":1450, |
| | | "patchState":0, |
| | | "isRotate":0, |
| | | "rackNo":1, |
| | | "glassPoint":{} |
| | | }, |
| | | {"isRemain":false, |
| | | "width":2070, |
| | | "height":725, |
| | | "realWidth":2070, |
| | | "realHeight":725, |
| | | "layer":1, |
| | | "totalLayer":2, |
| | | "orderSort":1, |
| | | "processId":"NG22091408A06", |
| | | "stockSort":1, |
| | | "polySort":6, |
| | | "markIcon":"", |
| | | "x":2070, |
| | | "y":1450, |
| | | "patchState":0, |
| | | "isRotate":0, |
| | | "rackNo":1, |
| | | "glassPoint":{} |
| | | }, |
| | | {"isRemain":true, |
| | | "width":2070, |
| | | "height":265, |
| | | "x":0, |
| | | "y":2175 |
| | | }, |
| | | {"isRemain":true, |
| | | "width":2070, |
| | | "height":265, |
| | | "x":2070, |
| | | "y":2175 |
| | | }, |
| | | {"isRemain":true, |
| | | "width":360, |
| | | "height":2440, |
| | | "x":4140, |
| | | "y":0 |
| | | }] |
| | | // 更新 store 数据 |
| | | if (result.layouts && result.layouts.length > 0) { |
| | | orderInfo.optimizeData.optimalResults = { |
| | | projectNo: result.projectNo, |
| | | glassThickness: result.glassThickness, |
| | | glassType: result.glassType, |
| | | totalQuantity: result.totalQuantity, |
| | | glassTotalQuantity: result.glassTotalQuantity, |
| | | glassTotalArea: result.glassTotalArea, |
| | | avgCutRate: result.avgCutRate, |
| | | lastCutRate: result.lastCutRate, |
| | | validCutRate: result.validCutRate, |
| | | layouts: result.layouts |
| | | }; |
| | | } |
| | | // 在这里就设置 originalFilm 数据 |
| | | const newOriginalFilm = []; |
| | | result.layouts.forEach(items => { |
| | | const existingItem = newOriginalFilm.find( |
| | | item => item.width === items.width && item.height === items.height |
| | | ); |
| | | |
| | | if (existingItem) { |
| | | existingItem.count += 1; |
| | | } else { |
| | | newOriginalFilm.push({ |
| | | width: items.width, |
| | | height: items.height, |
| | | upTrim: items.upTrim, |
| | | downTrim: items.downTrim, |
| | | leftTrim: items.leftTrim, |
| | | rightTrim: items.rightTrim, |
| | | stockCode: items.stockCode, |
| | | glassArea: items.glassArea, |
| | | glassQuantity: items.glassQuantity, |
| | | usageRate: items.usageRate, |
| | | count: 1 |
| | | }); |
| | | } |
| | | }); |
| | | originalFilm.value = newOriginalFilm; |
| | | orderInfo.optimizeData.originalFilm = newOriginalFilm; // 这一行很重要 |
| | | console.log('优化完成后设置 originalFilm:', newOriginalFilm); |
| | | // 更新利用率 |
| | | totalUtilizationRate.value = result.avgCutRate; |
| | | tailPieceRate.value = result.lastCutRate; |
| | | |
| | | // 显示成功提示 |
| | | ElMessage.success('优化完成'); |
| | | } else { |
| | | // 显示失败提示 |
| | | ElMessage.error(response.msg || '优化失败'); |
| | | } |
| | | ]}] |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | // 捕获网络错误 |
| | | console.error('优化请求失败:', error); |
| | | ElMessage.error('网络异常,请检查接口'); |
| | | }) |
| | | .finally(() => { |
| | | // 在请求完成时将进度条设为100% |
| | | progress.value = 100; |
| | | // 启用按钮 |
| | | document.getElementById("start").disabled = false; |
| | | // 显示完成按钮 |
| | | document.getElementById("complete").style.display = "block"; |
| | | showCompleteButton.value = true; |
| | | // 停止定时器 |
| | | pauseTimer(); |
| | | }); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | }; |
| | | |
| | | const pauseTimer = () => { |
| | | if (isRunning.value) { |
| | | clearInterval(intervalId); |
| | | isRunning.value = false; |
| | | } |
| | | }; |
| | | const resetTimer = () => { |
| | | router.push({path: '/main/glassOptimize/Optimization'}) |
| | | /*clearInterval(intervalId); |
| | | isRunning.value = false; |
| | | seconds.value = 0; |
| | | progress.value = 0;*/ |
| | | |
| | | const isSaving = ref(false); |
| | | |
| | | const saveOptimizeData = async () => { |
| | | // 检查是否有优化数据 |
| | | if(orderInfo.optimizeData !== null){ |
| | | try { |
| | | isSaving.value = true; |
| | | // 确保 originalFilm 数据已设置 |
| | | if (!orderInfo.optimizeData.originalFilm) { |
| | | orderInfo.optimizeData.originalFilm = originalFilm.value; |
| | | console.log('保存前设置 originalFilm:', originalFilm.value); |
| | | } |
| | | // 发送请求保存优化数据 |
| | | const res = await request.post(`/glassOptimize/saveOptimizeData/${props.optimizeData.projectNo}`, orderInfo.optimizeData); |
| | | |
| | | if (Number(res.code) === 200) { |
| | | ElMessage.success("保存成功"); |
| | | return true; // 保存成功 |
| | | } else { |
| | | ElMessage.warning(res.msg || "保存失败"); |
| | | return false; // 保存失败 |
| | | } |
| | | } catch (error) { |
| | | ElMessage.error("保存过程中发生错误"); |
| | | console.error("保存数据出错:", error); |
| | | return false; // 保存出错 |
| | | } finally { |
| | | // 无论成功或失败,都结束保存状态 |
| | | isSaving.value = false; |
| | | } |
| | | } else { |
| | | ElMessage.warning("无优化数据可保存"); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | const resetTimer = async () => { |
| | | // 先保存数据,保存成功后再跳转 |
| | | const isSaved = await saveOptimizeData(); |
| | | |
| | | if (isSaved) { |
| | | // 保存成功后跳转到优化界面 |
| | | router.push({path: '/main/glassOptimize/Optimization'}); |
| | | } else { |
| | | // 保存失败,给用户选择是否仍要离开 |
| | | ElMessageBox.confirm( |
| | | '数据保存失败,是否仍要离开当前页面?', |
| | | '提示', |
| | | { |
| | | confirmButtonText: '确定离开', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | } |
| | | ).then(() => { |
| | | // 用户确认离开 |
| | | router.push({path: '/main/glassOptimize/Optimization'}); |
| | | }).catch(() => { |
| | | // 用户取消,留在当前页面 |
| | | ElMessage.info('操作已取消'); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | watch( |
| | | ()=> [progress.value], |
| | | ([newValue])=> { |
| | | if(progress.value===10){ |
| | | orderInfo.optimizeData.optimalResults=mockData.value.data[0] |
| | | mockData.value.data[0].layouts.forEach(items=>{ |
| | | () => progress.value, |
| | | (newValue) => { |
| | | console.log('优化进度更新:', newValue); |
| | | } |
| | | ); |
| | | |
| | | // 根据唯一标识(如 id)查找是否已存在 |
| | | const existingItem = originalFilm.value.find(item => item["width"] === items["width"]&&item["height"] === items["height"]); |
| | | if (existingItem) { |
| | | // 存在:数量加1(假设字段为 count) |
| | | existingItem.count += 1; |
| | | } else { |
| | | // 不存在:新增到数组(初始化 count=1) |
| | | const array={ |
| | | width:items["width"], |
| | | height:items["height"], |
| | | upTrim:items["upTrim"], |
| | | downTrim:items["downTrim"], |
| | | leftTrim:items["leftTrim"], |
| | | rightTrim:items["rightTrim"], |
| | | stockCode:items["stockCode"], |
| | | count:1 |
| | | } |
| | | originalFilm.value.push(array); |
| | | } |
| | | |
| | | }) |
| | | orderInfo.optimizeData.originalFilm=originalFilm.value |
| | | totalUtilizationRate.value=mockData.value.data[0].avgCutRate*100 |
| | | tailPieceRate.value=mockData.value.data[0].layouts*100 |
| | | pauseTimer() |
| | | document.getElementById("complete").style.display="block" |
| | | document.getElementById("start").disabled=false |
| | | } |
| | | }); |
| | | |
| | | </script> |
| | | |
| | |
| | | <vxe-input class="input" v-model="props.quantity" disabled ></vxe-input> |
| | | <span>优化时长(秒):</span> |
| | | <span class="time-display">{{ formattedTime }}</span> |
| | | <el-button id="start" type="primary" style="margin-left: 20px" @click="startTimer">开始优化</el-button> |
| | | <!-- <el-button class="buttons" type="primary" @click="pauseTimer">暂停</el-button>--> |
| | | <el-button id="complete" class="buttons" type="primary" style="display: none" @click="resetTimer">完成</el-button> |
| | | <el-button |
| | | id="start" |
| | | type="primary" style="margin-left: 20px" |
| | | @click="startTimer" |
| | | :disabled="isRunning || isSaving" |
| | | :class="{ 'disabled-button': isRunning || isSaving }" |
| | | > |
| | | 开始优化 |
| | | </el-button> |
| | | <el-button |
| | | id="complete" |
| | | class="buttons" |
| | | type="primary" |
| | | :style="{ display: showCompleteButton ? 'inline-block' : 'none' }" |
| | | @click="resetTimer" |
| | | :disabled="isSaving" |
| | | :class="{ 'disabled-button': isSaving }" |
| | | > |
| | | {{ isSaving ? '保存中...' : '完成' }} |
| | | </el-button> |
| | | </div> |
| | | <br> |
| | | <!-- <div style="display: flex;margin-top: -10px"> |
| | |
| | | <div id="box"> |
| | | <span style="font-size: 20px">优化进度</span> |
| | | <div class="progress-bar"> |
| | | <el-progress :percentage="progress" |
| | | :text-inside="true" |
| | | :stroke-width="20" |
| | | status="success" |
| | | striped |
| | | striped-flow |
| | | duration="45"/> |
| | | <el-progress :percentage="progress" |
| | | :text-inside="true" |
| | | :stroke-width="20" |
| | | status="success" |
| | | :striped="true" |
| | | :striped-flow="progress < 100" |
| | | :duration="progress < 100 ? 45 : 0" |
| | | /> |
| | | </div> |
| | | <div style="height: 250px; margin-top: 20px; border: 2px solid #e6e6e6; padding: 10px; border-radius: 5px;"> |
| | | <span style="font-weight: bold">当前结果</span><br/> |
| | |
| | | height: 80%; |
| | | } |
| | | |
| | | .disabled-button { |
| | | opacity: 0.95 !important; |
| | | cursor: not-allowed !important; |
| | | } |
| | | |
| | | |
| | | </style> |