提交 实现玻璃优化报告下载部分功能,多出前端样式修改
| | |
| | | <template> |
| | | <div> |
| | | <el-button id="button" type="primary" @click="printReports" style="background: #409eff; position: fixed; top: 90px; right: 100px; padding: 20px; color: white; border: none; cursor: pointer; margin-right: 10px;"> |
| | | 预览 |
| | | </el-button> |
| | | <el-button id="button" type="primary" @click="handlePrint" style="position: fixed; top: 90px; right: 20px; padding: 20px; background: #409eff; color: white; border: none; border-radius: 5px; cursor: pointer;"> |
| | | 打印 |
| | | </el-button> |
| | |
| | | <div style="display: flex; align-items: center; gap: 20px; margin-bottom: 20px;"> |
| | | <span>工程编号:</span> |
| | | <el-input readonly placeholder="" style="width: 150px" v-model="processId"></el-input> |
| | | <el-checkbox v-model="config.plain"> |
| | | 切材率 |
| | | <el-checkbox v-model="config.printLayouts"> |
| | | 打印版图 |
| | | </el-checkbox> |
| | | <el-checkbox v-model="config.printReport"> |
| | | 打印报告 |
| | | </el-checkbox> |
| | | <div style="margin-right: 30px;"></div> |
| | | <span>布局选择:</span> |
| | | <el-select v-model="config.type" style="width: 120px;"> |
| | | <el-option v-for="type in linkTypes" :key="type" :value="type" /> |
| | | <el-select v-model="config.columnTypes" style="width: 120px;"> |
| | | <el-option v-for="type in columnTypes" :key="type" :value="type" /> |
| | | </el-select> |
| | | <el-button id="button" type="primary" @click="handlePrint" style="background: #409eff; color: white; border: none; cursor: pointer;"> |
| | | 预览 |
| | | </el-button> |
| | | <el-select v-model="config.rowTypes" style="width: 120px;"> |
| | | <el-option v-for="type in rowTypes" :key="type" :value="type" /> |
| | | </el-select> |
| | | </div> |
| | | <div style="display: flex; align-items: center; gap: 20px; margin-bottom: 20px;"> |
| | | <span>显示小片信息:</span> |
| | | <el-select v-model="config.glassInfo" style="width: 120px;"> |
| | | <el-option v-for="type in glassInfo" :key="type" :value="type" /> |
| | | </el-select> |
| | | <span>显示切割信息:</span> |
| | | <el-select v-model="config.cutInfo" style="width: 120px;"> |
| | | <el-option v-for="type in cutInfo" :key="type" :value="type" /> |
| | | </el-select> |
| | | </div> |
| | | |
| | | <div ref="printContainer" style="position: relative;"> |
| | |
| | | import { ref, onMounted, watch, reactive, inject } from 'vue'; |
| | | import RectRenderer from './page/RectRenderer.vue'; |
| | | import request from "@/utils/request"; |
| | | import {ElMessage, ElMessageBox} from "element-plus"; |
| | | import requestOptimize from "@/utils/requestOptimize"; |
| | | |
| | | const props = defineProps({ |
| | | project : null, |
| | |
| | | const savedProjectNo = localStorage.getItem('projectNo'); |
| | | const processId = ref(''); |
| | | const layoutData = ref(); |
| | | const optimizeUse = ref(); |
| | | const reportData = ref(); |
| | | const layoutSet = ref(); |
| | | const materialList = ref(); |
| | | const productList = ref(); |
| | | const dataLoaded = ref(false); |
| | | const materialDetails = ref(); |
| | | const injectedProjectNo = inject('projectNo', null); |
| | | const state = ref(); |
| | | const linkTypes = ['一列', '两列', '三列'] |
| | | const columnTypes = ['一列', '两列', '三列', '四列'] |
| | | const rowTypes = ['一行', '两行'] |
| | | const glassInfo = ['不显示', '显示在右侧', '显示在下侧'] |
| | | const cutInfo = ['不显示', '显示'] |
| | | |
| | | // 定义不同布局对应的尺寸 |
| | | const layoutDimensions = { |
| | |
| | | const currentPrintHeight = ref(layoutDimensions[printLayout.value].height); |
| | | |
| | | const selectLayout = () => { |
| | | request.post(`/glassOptimize/selectOptimizeResult/${processId.value}`) |
| | | request.post(`/glassOptimize/getOptimizeInfo/${processId.value}`) |
| | | .then((res) => { |
| | | if (res.code == 200) { |
| | | try { |
| | | layoutData.value = JSON.parse(res.data.data[0].Layouts); |
| | | materialDetails.value=res.data.optimizeUse; |
| | | dataLoaded.value=true; |
| | | layoutData.value = res.data.layouts; |
| | | optimizeUse.value=res.data.optimizeUse[0]; |
| | | // 添加控制台输出 |
| | | console.log('layoutData:', layoutData.value); |
| | | console.log('optimizeUse:', optimizeUse.value); |
| | | } catch (error) { |
| | | console.error("解析布局数据失败:", error); |
| | | } |
| | |
| | | }); |
| | | }; |
| | | |
| | | const selectReportData= () => { |
| | | request.post(`/glassOptimize/getReportData/${processId.value}`) |
| | | .then((res) => { |
| | | if (res.code == 200) { |
| | | try { |
| | | reportData.value = res.data.reportData[0]; |
| | | console.log('reportData:', reportData.value); |
| | | } catch (error) { |
| | | console.error("解析布局数据失败:", error); |
| | | } |
| | | } else { |
| | | console.error("请求失败,状态码:", res.code); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error("请求失败:", error); |
| | | }); |
| | | }; |
| | | |
| | | |
| | | const selectMaterialData= () => { |
| | | request.post(`/glassOptimize/materialInfo/${processId.value}`) |
| | | .then((res) => { |
| | | if (res.code == 200) { |
| | | try { |
| | | materialList.value = res.data.materialList[0]; |
| | | console.log('reportData:', materialList.value); |
| | | } catch (error) { |
| | | console.error("解析布局数据失败:", error); |
| | | } |
| | | } else { |
| | | console.error("请求失败,状态码:", res.code); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error("请求失败:", error); |
| | | }); |
| | | }; |
| | | |
| | | const selectProductData= () => { |
| | | request.post(`/glassOptimize/getProductList/${processId.value}`) |
| | | .then((res) => { |
| | | if (res.code == 200) { |
| | | try { |
| | | productList.value = res.data.productList; |
| | | console.log('productList:', productList.value); |
| | | } catch (error) { |
| | | console.error("解析布局数据失败:", error); |
| | | } |
| | | } else { |
| | | console.error("请求失败,状态码:", res.code); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error("请求失败:", error); |
| | | }); |
| | | }; |
| | | |
| | | const printReports = async() => { |
| | | try { |
| | | // 确保有数据可以提交 |
| | | if (!processId) { |
| | | ElMessage.warning('没有可打印的数据'); |
| | | return; |
| | | } |
| | | |
| | | // 映射 rowTypes 到 layoutRows |
| | | const layoutRowsMap = { |
| | | '一行': 1, |
| | | '两行': 2 |
| | | }; |
| | | |
| | | // 映射 columnTypes 到 layoutColumns |
| | | const layoutColumnsMap = { |
| | | '一列': 1, |
| | | '两列': 2, |
| | | '三列': 3, |
| | | '四列': 4 |
| | | }; |
| | | |
| | | // 映射 glassInfo 到 glassInfoShow |
| | | const glassInfoMap = { |
| | | '不显示': 0, |
| | | '显示在右侧': 1, |
| | | '显示在下侧': 2 |
| | | }; |
| | | |
| | | // 映射 cutInfo 到 cutInfoShow |
| | | const cutInfoMap = { |
| | | '不显示': 0, |
| | | '显示': 1 |
| | | }; |
| | | |
| | | const response = await requestOptimize.post('/api/reports', { |
| | | fileName: processId.value, |
| | | projectNo: processId.value, |
| | | companyName : '1', |
| | | glassThickness : optimizeUse.value.thickness, |
| | | glassType : optimizeUse.value.model, |
| | | quantity : String(optimizeUse.value.processingQuantity), |
| | | printLayouts : config.printLayouts ? '1' : '0', |
| | | printReport : config.printReport ? '1' : '0', |
| | | layouts : layoutData.value, |
| | | reportData: reportData.value, |
| | | materialList: materialList.value, |
| | | productList: productList.value, |
| | | layoutSet: { |
| | | layoutRows: layoutRowsMap[config.rowTypes] || 1, |
| | | layoutColumns: layoutColumnsMap[config.columnTypes] || 1, |
| | | glassInfoShow: glassInfoMap[config.glassInfo] || 0, |
| | | cutInfoShow: cutInfoMap[config.cutInfo] || 0 |
| | | } |
| | | |
| | | }, { |
| | | headers: { |
| | | 'Content-Type': 'application/json' |
| | | } |
| | | }); |
| | | |
| | | } catch (error) { |
| | | console.error('保存失败:', error); |
| | | ElMessage.error('保存失败,请稍后再试'); |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | const config = reactive({ |
| | | type: '两列', |
| | | columnTypes: '两列', |
| | | rowTypes: '两行', |
| | | plain: true, |
| | | printLayouts: true, |
| | | printReport: true, |
| | | glassInfo: '不显示', |
| | | cutInfo: '显示' |
| | | |
| | | }) |
| | | |
| | | onMounted(() => { |
| | |
| | | |
| | | if (processId.value) { |
| | | selectLayout(); |
| | | selectReportData(); |
| | | selectMaterialData(); |
| | | selectProductData(); |
| | | } |
| | | }); |
| | | |
| | |
| | | |
| | | <div id="project-list"> |
| | | <div style="width: 100%;height: 100%"> |
| | | <h1>工程列表</h1> |
| | | <h2>工程列表</h2> |
| | | <vxe-grid |
| | | size="small" |
| | | height="100%" |
| | |
| | | </template> |
| | | |
| | | <template #toolbar_buttons> |
| | | <h1>膜系筛选:</h1> |
| | | <h2>膜系筛选:</h2> |
| | | <el-select v-model="optionVal" clearable default-value="default_city" placeholder="选择膜系" |
| | | style="width: 120px"> |
| | | <el-option |
| | |
| | | |
| | | <template> |
| | | <div style="width: 100%;height: 100%"> |
| | | <h1>流程卡详情</h1> |
| | | <h2>流程卡详情</h2> |
| | | <vxe-grid |
| | | size="small" |
| | | height="100%" |
| | |
| | | return Result.seccess(glassOptimizeService.saveOptimizeResult(object,projectId)); |
| | | } |
| | | |
| | | @ApiOperation("查询报告数据接口") |
| | | @PostMapping("/getReportData/{processId}") |
| | | public Result getReportData(@PathVariable String processId){ |
| | | return Result.seccess(glassOptimizeService.getReportDataSv(processId)); |
| | | } |
| | | |
| | | @ApiOperation("查询物料信息接口") |
| | | @PostMapping("/materialInfo/{processId}") |
| | | public Result materialInfo( |
| | | @PathVariable String processId){ |
| | | return Result.seccess(glassOptimizeService.getMaterialInfoSv(processId)); |
| | | } |
| | | |
| | | |
| | | @ApiOperation("查询产品列表接口") |
| | | @PostMapping("/getProductList/{processId}") |
| | | public Result getProductList( |
| | | @PathVariable String processId){ |
| | | return Result.seccess(glassOptimizeService.getProductListSv(processId)); |
| | | } |
| | | |
| | | @ApiOperation("查询优化结果接口") |
| | | @PostMapping("/selectOptimizeResult/{processId}") |
| | |
| | | void addUpdateOffcut(Map<String, Object> detail, String processId, String glassType, String glassThickness, int stockId); |
| | | |
| | | void updateProjectOptimize(String projectId, Integer states, Map<String, Object> optimalResults); |
| | | |
| | | List<Map<String, Object>> getReportDataProcessIdSv(String processId); |
| | | |
| | | List<Map<String, Object>> getPeriMeterDataSv(String processId); |
| | | |
| | | List<Map<String, Object>> getMaterialInfoSv(String processId); |
| | | |
| | | List<Map<String, Object>> getProductListSv(String processId); |
| | | |
| | | List<Map<String, Object>> selectProjectList(String processId); |
| | | |
| | | List<Map<String, Object>> materialOptimizeUse(String processId); |
| | | } |
| | |
| | | // Map<String, Object> result = new HashMap<>(); |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("layouts", layouts); |
| | | result.put("optimizeUse", glassOptimizeMapper.materialStoreOptimizeUse(processId)); |
| | | result.put("optimizeUse", glassOptimizeMapper.materialOptimizeUse(processId)); |
| | | return result; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | public Map<String, Object> getReportDataSv(String processId) { |
| | | Map<String, Object> perimap = new HashMap<>(); |
| | | perimap.put("peridata", glassOptimizeMapper.getPeriMeterDataSv(processId)); |
| | | |
| | | Map<String, Object> map = new HashMap<>(); |
| | | Object layoutSetObj = glassOptimizeMapper.getReportDataProcessIdSv(processId); |
| | | map.put("reportData", layoutSetObj); |
| | | List<Map<String, Object>> peridata = (List<Map<String, Object>>) perimap.get("peridata"); |
| | | double totalPerimeter = 0.0; |
| | | if (peridata != null && !peridata.isEmpty()) { |
| | | for (Map<String, Object> perimeterData : peridata) { |
| | | if (perimeterData.containsKey("perimeter") && perimeterData.get("perimeter") != null) { |
| | | try { |
| | | Object perimeterObj = perimeterData.get("perimeter"); |
| | | if (perimeterObj instanceof Number) { |
| | | totalPerimeter += ((Number) perimeterObj).doubleValue(); |
| | | } else { |
| | | totalPerimeter += Double.parseDouble(perimeterObj.toString()); |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | System.err.println("无法解析周长数据: " + perimeterData.get("perimeter")); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (layoutSetObj instanceof List) { |
| | | List<Map<String, Object>> layoutSet = (List<Map<String, Object>>) layoutSetObj; |
| | | if (!layoutSet.isEmpty()) { |
| | | layoutSet.get(0).put("rectanglePerimeter", totalPerimeter); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | public Map<String, Object> getMaterialInfoSv(String processId) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("materialList", glassOptimizeMapper.getMaterialInfoSv(processId)); |
| | | return map; |
| | | } |
| | | |
| | | public Map<String, Object> getProductListSv(String processId) { |
| | | Map<String, Object> productMap = new HashMap<>(); |
| | | List<Map<String, Object>> productInfo = glassOptimizeMapper.selectProjectList(processId); |
| | | productMap.put("productInfo", productInfo); |
| | | Map<String, Object> map = new HashMap<>(); |
| | | |
| | | if (productInfo != null && !productInfo.isEmpty()) { |
| | | // 按照 processCard 分组 |
| | | Map<String, List<Map<String, Object>>> groupedByProcessCard = new HashMap<>(); |
| | | for (Map<String, Object> item : productInfo) { |
| | | String processCard = (String) item.get("processCard"); |
| | | if (processCard != null) { |
| | | groupedByProcessCard.computeIfAbsent(processCard, k -> new ArrayList<>()).add(item); |
| | | } |
| | | } |
| | | |
| | | // 为每个 processCard 计算统计信息 |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (Map.Entry<String, List<Map<String, Object>>> entry : groupedByProcessCard.entrySet()) { |
| | | String processCard = entry.getKey(); |
| | | List<Map<String, Object>> items = entry.getValue(); |
| | | |
| | | // 计算统计信息 |
| | | double longestSide = 0; |
| | | double shortestSide = Double.MAX_VALUE; |
| | | int specQuantity = items.size(); |
| | | int totalQuantity = 0; |
| | | |
| | | // 使用 BigDecimal 精确计算面积 |
| | | BigDecimal totalArea = BigDecimal.ZERO; |
| | | |
| | | for (Map<String, Object> item : items) { |
| | | // 安全获取长和宽 |
| | | Number widthObj = (Number) item.get("width"); |
| | | Number heightObj = (Number) item.get("height"); |
| | | |
| | | if (widthObj == null || heightObj == null) { |
| | | continue; |
| | | } |
| | | |
| | | double width = widthObj.doubleValue(); |
| | | double height = heightObj.doubleValue(); |
| | | |
| | | // 更新最长边和最短边 |
| | | double maxSide = Math.max(width, height); |
| | | double minSide = Math.min(width, height); |
| | | |
| | | if (maxSide > longestSide) { |
| | | longestSide = maxSide; |
| | | } |
| | | if (minSide < shortestSide) { |
| | | shortestSide = minSide; |
| | | } |
| | | |
| | | // 安全获取数量 |
| | | Number quantityObj = (Number) item.get("quantity"); |
| | | if (quantityObj != null) { |
| | | totalQuantity += quantityObj.intValue(); |
| | | } |
| | | |
| | | // 安全获取面积 —— 使用 BigDecimal 精确累加 |
| | | Object areaObj = item.get("Area"); |
| | | if (areaObj != null) { |
| | | // 关键:通过 toString() 转为字符串再构造 BigDecimal,避免 double 精度损失 |
| | | BigDecimal area = new BigDecimal(areaObj.toString()); |
| | | totalArea = totalArea.add(area); |
| | | } |
| | | } |
| | | |
| | | // 处理 shortestSide 的边界情况 |
| | | if (shortestSide == Double.MAX_VALUE) { |
| | | shortestSide = 0; |
| | | } |
| | | |
| | | // 构造返回数据 |
| | | Map<String, Object> resultMap = new HashMap<>(); |
| | | resultMap.put("processCard", processCard); |
| | | resultMap.put("longestSide", longestSide); |
| | | resultMap.put("shortestSide", shortestSide); |
| | | resultMap.put("specQuantity", specQuantity); |
| | | resultMap.put("totalQuantity", totalQuantity); |
| | | resultMap.put("totalArea", totalArea); |
| | | |
| | | result.add(resultMap); |
| | | } |
| | | |
| | | map.put("productList", result); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | WHERE |
| | | project_no = #{projectId} |
| | | </select> |
| | | <select id="getReportDataProcessIdSv" resultType="java.util.Map" parameterType="java.lang.String"> |
| | | SELECT |
| | | op.project_no as projectId, |
| | | op.glass_total as rectangleQuantity, |
| | | '0' as otherShapeQuantity, |
| | | op.glass_total_area as rectangleArea, |
| | | '0' as otherShapeArea, |
| | | '0' as otherShapePerimeter |
| | | FROM |
| | | pp.optimize_project as op |
| | | WHERE |
| | | op.project_no = #{processId} |
| | | </select> |
| | | <select id="getPeriMeterDataSv" resultType="java.util.Map" parameterType="java.lang.String"> |
| | | SELECT |
| | | od.id, |
| | | od.project_no, |
| | | od.p_width, |
| | | od.p_height, |
| | | (od.p_width + od.p_height)*2 AS perimeter |
| | | FROM |
| | | pp.optimize_detail as od |
| | | WHERE |
| | | od.project_no = #{processId} |
| | | </select> |
| | | <select id="getMaterialInfoSv" resultType="java.util.Map" parameterType="java.lang.String"> |
| | | SELECT |
| | | ou.raw_stock_code AS code, |
| | | ou.use_count AS quantity, |
| | | ou.width, |
| | | ou.height, |
| | | ou.width*ou.height*ou.use_count/1000000.0 as useArea, |
| | | op.glass_total_area as totalArea |
| | | FROM |
| | | pp.optimize_use ou |
| | | INNER JOIN pp.optimize_project op on ou.project_no = op.project_no |
| | | WHERE |
| | | ou.project_no = #{processId} and ou.state=1 |
| | | </select> |
| | | <select id="getProductListSv" resultType="java.util.Map" parameterType="java.lang.String"> |
| | | |
| | | </select> |
| | | <select id="selectProjectList" resultType="java.util.Map" parameterType="java.lang.String"> |
| | | ( SELECT |
| | | c.project_no, |
| | | c.quantity AS quantity, |
| | | d.child_width AS width, |
| | | d.child_height AS height, |
| | | concat( c.process_id, '-', c.technology_number ) AS processCard, |
| | | round( d.area * c.quantity, 4 ) AS Area, |
| | | c.order_number |
| | | FROM |
| | | pp.flow_card c |
| | | LEFT JOIN sd.order_glass_detail d ON c.order_id = d.order_id |
| | | AND c.order_number = d.order_number |
| | | AND c.technology_number = d.technology_number |
| | | WHERE |
| | | c.project_no IS NOT NULL |
| | | AND c.project_no = #{processId} |
| | | |
| | | ORDER BY |
| | | c.process_id, |
| | | c.order_number |
| | | ) UNION |
| | | ( |
| | | SELECT |
| | | c.project_no, |
| | | c.patch_num AS quantity, |
| | | d.child_width AS width, |
| | | d.child_height AS height, |
| | | concat( c.process_id, '-', c.technology_number ) AS processCard, |
| | | round( d.area * c.patch_num, 4 ) AS Area, |
| | | c.order_sort |
| | | FROM |
| | | pp.patch_log c |
| | | LEFT JOIN sd.order_glass_detail d ON c.order_id = d.order_id |
| | | AND c.order_sort = d.order_number |
| | | AND c.technology_number = d.technology_number |
| | | WHERE |
| | | c.project_no IS NOT NULL |
| | | AND c.project_no = #{processId} |
| | | |
| | | ORDER BY |
| | | c.process_id, |
| | | c.order_sort) |
| | | </select> |
| | | <select id="materialOptimizeUse" resultType="java.util.Map"> |
| | | select ou.raw_stock_code AS id, |
| | | ou.use_count AS processingQuantity, |
| | | ou.width, |
| | | ou.height, |
| | | ou.left_trim as leftTrim, |
| | | ou.down_trim as downTrim, |
| | | ou.up_trim as upTrim, |
| | | ou.right_trim as rightTrim, |
| | | JSON_UNQUOTE(JSON_EXTRACT(ms.json, '$.thickness')) AS thickness, |
| | | JSON_UNQUOTE(JSON_EXTRACT(ms.json, '$.name')) AS name, |
| | | JSON_UNQUOTE(JSON_EXTRACT(ms.json, '$.model')) AS model |
| | | from pp.optimize_use ou |
| | | left join mm.material_store ms on ou.raw_stock_code=ms.id where project_no=#{projectNumber} and state=1 |
| | | </select> |
| | | |
| | | |
| | | </mapper> |