chenlu
2025-08-11 6bb30b735e52488fd3d57bfa2d5f6705f7326a98
Merge branch 'master' of http://10.153.19.25:10105/r/ERP_override
11个文件已修改
1个文件已添加
662 ■■■■■ 已修改文件
north-glass-erp/northglass-erp/src/components/sd/order/SelectAlienEditor.vue 381 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/northglass-erp/src/hook/index.js 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/northglass-erp/src/views/mm/ingredientStock/SelectIngredientsStock.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/northglass-erp/src/views/pp/glassOptimize/OptimizeControl.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/northglass-erp/src/views/pp/replenish/PrintReplenishFlowCard.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/northglass-erp/src/views/pp/reportingWorks/AddReportingWork.vue 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/src/main/java/com/example/erp/controller/pp/GlassOptimizeController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/src/main/java/com/example/erp/mapper/pp/GlassOptimizeMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/src/main/java/com/example/erp/service/pp/GlassOptimizeService.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/src/main/resources/mapper/pp/FolwCard.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/src/main/resources/mapper/pp/GlassOptimize.xml 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/src/main/resources/mapper/pp/ReportingWork.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
north-glass-erp/northglass-erp/src/components/sd/order/SelectAlienEditor.vue
New file
@@ -0,0 +1,381 @@
<script setup>
import {computed, onMounted, onUpdated, reactive, ref, watch} from "vue"
import {filterChanged} from "@/hook"
import {useI18n} from "vue-i18n"
import {ElMessage, ElMessageBox,} from "element-plus"
import request from "@/utils/request"
import {useRouter,useRoute} from "vue-router"
import {Ellipse, Leafer, Line, Path, Polygon} from "leafer-ui";
import {round} from "xe-utils";
import DxfParser from "dxf-parser";
import { saveAs } from 'file-saver';
import DXFWriter from 'dxf-writer';
const { t } = useI18n()
const router = useRouter()
const route = useRoute()
let width = ref("")
let height = ref("null")
let rowIndex = ref(null)
const xGrid = ref()
let fileName=ref(null)
let fileDate=ref(null)
let dxfData=ref(null)
let state=ref(false)
let points=ref([])
let data1=ref(0);let data2=ref(0);let data3=ref(0);let data4=ref(0)
let data5=ref(0);let data6=ref(0);let data7=ref(0);let data8=ref(0)
let datas1=ref(0);let datas2=ref(0);let datas3=ref(0);let datas4=ref(0)
let datas5=ref(0);let datas6=ref(0);let datas7=ref(0);let datas8=ref(0)
let big=0
let leafer;
let parsedDXFData = ref([]);
let orderDetailWidth=ref(0)
let orderDetailHeight=ref(0)
let widthAgv=ref(0)
let heightAgv=ref(0)
const ongetprojectOrder = (row) => {
  if(row==undefined||row.width==null){
    const main = document.getElementById('main2')
    const width = document.getElementById('width2')
    const height = document.getElementById('height2')
    main.style.backgroundColor = "#ffffff"
    width.innerHTML = 0
    height.innerHTML = 0
    if (leafer !== undefined) {
      leafer.clear()
    }
    return
  }
  if (row.fileName == null || row.fileName == "") {
    orderDetailWidth.value = row.width
    orderDetailHeight.value = row.height
    const main = document.getElementById('main2')
    const width = document.getElementById('width2')
    const height = document.getElementById('height2')
    if (orderDetailWidth.value / 400 > orderDetailHeight.value / 200) {
      big = orderDetailWidth.value / 400
    } else {
      big = orderDetailHeight.value / 200
    }
    let widthAgv = orderDetailWidth.value / big
    let heightAgv = orderDetailHeight.value / big
    main.style.width = widthAgv + "px"
    main.style.height = heightAgv + "px"
    main.style.backgroundColor = "#8d9095"
    width.innerHTML = orderDetailWidth.value
    height.innerHTML = orderDetailHeight.value
    datas2.value = heightAgv
    datas8.value = heightAgv
    datas5.value = widthAgv
    datas7.value = widthAgv
    if (leafer !== undefined) {
      leafer.clear()
    }
    leafer = new Leafer({view: 'canva2'})
    points.value = [0, heightAgv, 0, 0, widthAgv, 0, widthAgv, heightAgv]
    const polygon = new Polygon({
      points: points.value,
      fill: '#32cd79',
      origin: [0, 0]
    })
    setTimeout(() => {
      leafer.add(polygon);
    }, 30)
    state.value = true
  } else {
    const b64Data = row.fileData;
    const byteCharacters = atob(b64Data);
    const parser = new DxfParser();
    dxfData.value = parser.parseSync(byteCharacters)
    state.value = false
    handleFileUpload()
  }
}
  function toBottomOrigin(y, canvasHeight) {
    return canvasHeight - y; // 将左上角Y坐标转换为左下角坐标系
  }
  const handleFileUpload = () => {
    const main = document.getElementById('main2')
    const width = document.getElementById('width2')
    const height = document.getElementById('height2')
    if (leafer !== undefined) {
      leafer.clear()
    }
    leafer = new Leafer({view: 'canva2'});
    try {
      let type = 0;
      let minX = Infinity, minY = Infinity;
      let maxX = -Infinity, maxY = -Infinity;
      dxfData.value.entities.forEach(entity => {
        if (entity.type === 'LINE' || entity.type === 'LWPOLYLINE') {
          entity.vertices.forEach(vertices => {
            minX = Math.min(vertices.x, minX);
            minY = Math.min(vertices.y, minY);
            maxX = Math.max(vertices.x, maxX);
            maxY = Math.max(vertices.y, maxY);
          })
        }
        if (entity.type === 'ARC') {
          type = 1
          const center = {x: entity.center.x, y: entity.center.y};
          const radius = entity.radius;
          const startAngle = entity.startAngle * (180 / Math.PI);
          const endAngle = entity.endAngle * (180 / Math.PI);
          const points = [];
          const steps = 32;
          for (let i = 0; i <= steps; i++) {
            const angle = startAngle + (endAngle - startAngle) * (i / steps);
            const x = center.x + radius * Math.cos(angle * Math.PI / 180);
            const y = center.y + radius * Math.sin(angle * Math.PI / 180);
            points.push({x, y});
          }
          points.forEach(p => {
            minX = Math.min(minX, p.x);
            minY = Math.min(minY, p.y);
            maxX = Math.max(maxX, p.x);
            maxY = Math.max(maxY, p.y);
          });
        }
        if (entity.type === 'CIRCLE') {
          type = 1
          minX = Math.min(minX, entity.center.x - entity.radius);
          minY = Math.min(minY, entity.center.y - entity.radius);
          maxX = Math.max(maxX, entity.center.x + entity.radius);
          maxY = Math.max(maxY, entity.center.y + entity.radius);
        }
      });
      if ((maxX - minX) / 400 > (maxY - minY) / 200) {
        big = (maxX - minX) / 400
      } else {
        big = (maxY - minY) / 200
      }
      Object.values(dxfData.value.entities).forEach(entity => {
        switch (entity.type) {
          case 'LINE':
            main.style.width = (maxX - minX) / big + "px"
            main.style.height = (maxY - minY) / big + "px"
            main.style.backgroundColor = "#8d9095"
            width.innerHTML = round(maxX - minX, 2)
            height.innerHTML = round(maxY - minY, 2)
            const line = new Line({
              points: [(entity.vertices[0].x - minX) / big, ((maxY - minY) - (entity.vertices[0].y - minY)) / big,
                (entity.vertices[1].x - minX) / big, ((maxY - minY) - (entity.vertices[1].y - minY)) / big],
              stroke: '#f00',
              strokeWidth: 1
            })
            setTimeout(() => {
              leafer.add(line);
            }, 30);
            break;
          case 'LWPOLYLINE':
            main.style.width = (maxX - minX) / big + "px"
            main.style.height = (maxY - minY) / big + "px"
            main.style.backgroundColor = "#8d9095"
            width.innerHTML = round(maxX - minX, 2)
            height.innerHTML = round(maxY - minY, 2)
            let point = entity.vertices.map(v => [
              (v.x - minX) / big,
              toBottomOrigin((v.y - minY) / big, (maxY - minY) / big),
            ]).flat()
            if (type == 1) {
              const polygon = new Polygon({
                points: point,
                stroke: '#f00'
              })
              setTimeout(() => {
                leafer.add(polygon);
              }, 30);
            } else {
              const polygon = new Polygon({
                points: point,
                fill: "#32cd79"
              })
              setTimeout(() => {
                leafer.add(polygon);
              }, 30);
            }
            break;
          case 'CIRCLE':
            let CIRCLEX = (entity.center.x - minX - entity.radius) / big
            let CIRCLEY = ((maxY - minY) - (entity.center.y - minY + entity.radius)) / big
            if (big < (entity.radius * 2) / 400) {
              big = (entity.radius * 2) / 400
              main.style.width = entity.radius * 2 / big + "px"
              main.style.height = entity.radius * 2 / big + "px"
              width.innerHTML = round(entity.radius * 2, 2)
              height.innerHTML = round(entity.radius * 2, 2)
              CIRCLEX = 0
              CIRCLEY = 0
            }
            const ellipse = new Ellipse({
              x: CIRCLEX,
              y: CIRCLEY,
              width: entity.radius * 2 / big,
              height: entity.radius * 2 / big,
              //fill: "#32cd79"
              stroke: '#f00',
            })
            setTimeout(() => {
              leafer.add(ellipse);
            }, 30);
            break;
          case 'ELLIPSE':
            console.log(entity)
            const {majorAxisEndPoint, axisRatio} = entity;
            const dx = majorAxisEndPoint.x;
            const dy = majorAxisEndPoint.y;
            const a = Math.sqrt(dx ** 2 + dy ** 2);
            const c = a * axisRatio;
            const θ = Math.atan2(dy, dx);
            const l = axisRatio * (180 / Math.PI);
            if ((a * 2) / 400 > (c * 2) / 200) {
              big = (a * 2) / 400
            } else {
              big = (c * 2) / 200
            }
            main.style.width = a * 2 / big + "px"
            main.style.height = c * 2 / big + "px"
            width.innerHTML = round(a * 2, 2)
            height.innerHTML = round(c * 2, 2)
            const ellipse2 = new Ellipse({
              width: a * 2 / big,
              height: c * 2 / big,
              fill: "#32cd79",
            })
            setTimeout(() => {
              leafer.add(ellipse2);
            }, 30);
            break;
          case 'ARC':
            const center = {x: entity.center.x, y: entity.center.y};
            const radius = entity.radius;
            const startAngle = entity.startAngle * (180 / Math.PI);
            const endAngle = entity.endAngle * (180 / Math.PI);
            if ((maxX - minX) / 400 > (maxY - minY) / 200) {
              big = (maxX - minX) / 400
            } else {
              big = (maxY - minY) / 200
            }
            // 计算圆弧的起点和终点
            const startX = (center.x + radius * Math.cos(entity.startAngle) - minX);
            const startY = (maxY - minY) - ((center.y + radius * Math.sin(entity.startAngle)) - minY);
            const endX = (center.x + radius * Math.cos(entity.endAngle) - minX);
            const endY = (maxY - minY) - ((center.y + radius * Math.sin(entity.endAngle)) - minY);
            // 创建圆弧路径
            const path = new Path({
              path: `M ${startX / big} ${startY / big} A ${radius / big} ${radius / big} 0 ${endAngle - startAngle > 180 ? 1 : 0} 0 ${endX / big} ${endY / big}`,
              stroke: '#f00',
              strokeWidth: 1,
            });
            setTimeout(() => {
              leafer.add(path);
            }, 30);
            break;
        }
      })
    } catch (error) {
      console.error('解析DXF文件时出错:', error);
    }
  };
  const validate = async () => {
    data1.value = 0
    data2.value = 0
    data3.value = 0
    data4.value = 0
    data5.value = 0
    data6.value = 0
    data7.value = 0
    data8.value = 0
    big = 0
    return true
  }
defineExpose({
  validate,
  ongetprojectOrder
})
</script>
<template>
  <div style="width: 404px;height: 204px;border: 2px solid #000;float: left;
              position: relative;display: flex;justify-content: center;align-content: center;margin-left: 80px;margin-top: 10px;">
    <div id="main2" ref="parent"  >
      <canvas  id="canva2" ></canvas>
    </div>
  </div>
  <div id="width2" style="height: 20px;position: absolute;top: -8px;left: 250px;">{{orderDetailWidth}}</div>
  <div id="height2" style="width: 60px;position: absolute;top: 95px;left: 20px;">{{orderDetailHeight}}</div>
</template>
<style scoped>
.contactNumber{
  width: 60px;
  height:20px;
  border: none;
  box-shadow: none;
  font-size: 15px;
}
.custom-file-upload {
  border: 1px solid #ccc;
  display: inline-block;
  padding: 6px 12px;
  cursor: pointer;
  background-color: #f9f9f9;
}
#mains {
  position: relative;
}
</style>
north-glass-erp/northglass-erp/src/hook/index.js
@@ -30,4 +30,25 @@
    return true
}
export {changeFilterEvent,filterChanged}
const filterChangeds = ({ option, row, column }) => {
    if (option.data) {
        // 将筛选关键词统一转为小写
        const searchStr = option.data.toLowerCase();
        if (column.field.indexOf('.') > -1) {
            let array = column.field.split('.');
            // 获取要比较的值并转为字符串后再转小写
            const value = row[array[0]]?.[array[1]];
            const valueStr = (value?.toString() || '').toLowerCase();
            return valueStr.indexOf(searchStr) > -1;
        } else {
            // 获取要比较的值并转为字符串后再转小写
            const value = row[column.field];
            const valueStr = (value?.toString() || '').toLowerCase();
            return valueStr.indexOf(searchStr) > -1;
        }
    }
    return true;
}
export {changeFilterEvent,filterChanged,filterChangeds}
north-glass-erp/northglass-erp/src/views/mm/ingredientStock/SelectIngredientsStock.vue
@@ -9,7 +9,7 @@
import {Search} from "@element-plus/icons-vue";
import { useI18n } from 'vue-i18n'
import {addListener, toolbarButtonClickEvent} from "@/hook/mouseMove";
import {changeFilterEvent,filterChanged} from "@/hook"
import {changeFilterEvent,filterChanged,filterChangeds} from "@/hook"
import {divideAuto, multiply} from "@/utils/decimal";
import companyInfo from "@/stores/sd/companyInfo";
import footSum from "@/hook/footSum";
@@ -116,7 +116,12 @@
      gridOptions.columns=arr.slice()
      for (let i=0;i<BasicData.value.length;i++){
        let aa={field: "json."+BasicData.value[i].OperateType, width: '150',title: BasicData.value[i].OperateTypeName, sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChanged}
        let aa=null
        if(BasicData.value[i].OperateType==="name"){
          aa={field: "json."+BasicData.value[i].OperateType, width: '150',title: BasicData.value[i].OperateTypeName, sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChangeds}
        }else{
          aa={field: "json."+BasicData.value[i].OperateType, width: '150',title: BasicData.value[i].OperateTypeName, sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChanged}
        }
        gridOptions.columns.push(aa)
      }
@@ -232,7 +237,12 @@
      gridOptions.columns=arr.slice()
      for (let i=0;i<BasicData.value.length;i++){
        let aa={field: "json."+BasicData.value[i].OperateType, width: '150',title: BasicData.value[i].OperateTypeName, sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChanged}
        let aa=null
        if(BasicData.value[i].OperateType==="model"){
           aa={field: "json."+BasicData.value[i].OperateType, width: '150',title: BasicData.value[i].OperateTypeName, sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChanged}
        }else{
           aa={field: "json."+BasicData.value[i].OperateType, width: '150',title: BasicData.value[i].OperateTypeName, sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChanged}
        }
        gridOptions.columns.push(aa)
north-glass-erp/northglass-erp/src/views/pp/glassOptimize/OptimizeControl.vue
@@ -33,6 +33,7 @@
// 添加用于存储库存数据的响应式变量
const inventoryData = ref([]);
const optimizeLayouts = ref(null);
// 从 localStorage 读取库存数据
const loadInventoryData = () => {
@@ -88,10 +89,41 @@
      });
};
const selectOptimizeInfo = () => {
  request.post(`/glassOptimize/getOptimizeInfo/${processId}`)
      .then((res) => {
        if ((res.code === 200 || res.code === '200') && res.data && res.data.layouts) {
          try {
            // 正确赋值给外层的响应式变量
            optimizeLayouts.value = res.data;
            console.log("布局数据:", optimizeLayouts.value);
            // 验证layouts数据
            if (res.data.layouts && res.data.layouts.length > 0) {
              console.log("layouts数组:", res.data.layouts);
            }
          } catch (error) {
            console.error("数据解析失败:", error);
            ElMessage.error("数据解析失败: " + error.message);
          }
        } else {
          ElMessage.warning("未找到优化数据");
        }
      })
      .catch((error) => {
        console.error("请求失败:", error);
        ElMessage.error(t('basicData.msg.requestFailed'));
      });
};
onMounted(() => {
  // 读取库存数据
  loadInventoryData();
  selectLayout();
  selectOptimizeInfo();
});
const submitLayouts = async () => {
@@ -101,7 +133,7 @@
      ElMessage.warning('没有可保存的数据');
      return;
    }
    console.log("提交数据:", layoutCutData.value);
    console.log("提交数据:", optimizeLayouts);
    const response = await requestOptimize.post('api/cutFiles', {
      fileName: processId,
      glassThickness:inventoryData.value[0].thickness,
@@ -110,7 +142,7 @@
      fileType:"OPT",
      fileSaveMode:1,
      glassIdMode:1,
      layouts: layoutCutData.value.layouts
      layouts: optimizeLayouts.value.layouts
    }, {
      headers: {
        'Content-Type': 'application/json'
north-glass-erp/northglass-erp/src/views/pp/replenish/PrintReplenishFlowCard.vue
@@ -337,6 +337,8 @@
    },
    {field: 'technology_number', title: t('processCard.technologyNumber'), showOverflow: "ellipsis",
      width:90},
    {field: 'child_width', title: t('order.width'), width:90,filters: [{data: ''}],slots: {filter: 'num1_filter'}, filterMethod: filterChanged,},
    {field: 'child_height', title: t('order.height'), width:90,filters: [{data: ''}],slots: {filter: 'num1_filter'}, filterMethod: filterChanged,},
    {
      field: 'glassNumber',
      title: t('reportingWorks.glassNumber'),
@@ -359,6 +361,7 @@
    {field: 'product_name', title: t('order.product'),width:110},
    {field: 'glass_child', title: t('reportingWorks.glassChild'),width:110},
    {field: 'reporting_work_id', title: t('reportingWorks.reportingWorkId'),width:120},
    {field: 'create_time', title: t('basicData.reportData'),width:120},
  ],//表头按钮
  toolbarConfig: {
north-glass-erp/northglass-erp/src/views/pp/reportingWorks/AddReportingWork.vue
@@ -440,19 +440,34 @@
          const completedNum =
              (row.completedQuantity === undefined || row.completedQuantity===null || row.completedQuantity==='') ? 0 : row.completedQuantity
          //
          const okVal = completedSum - totalQuantity
          const okVal = completedSum - totalQuantity + row.breakageQuantity
          //当可操作数量为0,并且完工数量不等于可完工数量时
          if(row.minQuantity===0 && val!==totalQuantity ){
          if(row.minQuantity===0 && val!==(totalQuantity-row.breakageQuantity) ){
            return new Error(`${t('reportingWorks.pleaseNumber12')} ${okVal}+${val}=${okVal+val}\n
                              ${t('reportingWorks.pleaseNumber13')} ${nextQuantitySum}\n
                              ${t('reportingWorks.pleaseNumber14')}
            `)
          }
          if(titleUploadData.value.reportingWorkId!=null  && (val>totalQuantity ||  val<(row.quantity-row.minQuantity) )){
            return new Error(`${row.quantity-row.minQuantity}
            <=val<=
            ${row.quantity}`)
          if(titleUploadData.value.reportingWorkId!=null){
            if(row.completedQuantityComputed>=row.minQuantity ){
              if((val<(row.completedQuantityComputed-row.minQuantity || val>=row.completedQuantityComputed))){
                return new Error(`${row.completedQuantityComputed-row.minQuantity}
                                  <=val<=
                                  ${row.completedQuantityComputed}`)
              }
            }else{
              if((val>row.completedQuantityComputed)){
                return new Error(`val
                                  <=
                                  ${row.completedQuantityComputed}`)
              }
            }
          }
        }
      }
north-glass-erp/src/main/java/com/example/erp/controller/pp/GlassOptimizeController.java
@@ -263,6 +263,13 @@
        return  Result.seccess(glassOptimizeService.selectOptimizeResult(processId));
    }
    @ApiOperation("查询优化结果信息接口")
    @PostMapping("/getOptimizeInfo/{processId}")
    public Result getOptimizeInfo(
            @PathVariable String processId){
        return  Result.seccess(glassOptimizeService.getOptimizeInfoSv(processId));
    }
    @ApiOperation("更新优化结果接口")
    @PostMapping("/updateOptimizeResult/{processId}")
    public Result updateOptimizeResult(
north-glass-erp/src/main/java/com/example/erp/mapper/pp/GlassOptimizeMapper.java
@@ -199,4 +199,12 @@
    Map<String, Object> getGlassInfo(String projectId);
    void addOptimizeOffcut(Map<String, Object> map, String projectId, String glassType, String glassThickness);
    List<Map<String, Object>> getOptimizeLayoutsInfo(String processId);
    List<Map<String, Object>> getOptimizeDetailsInfo(String processId);
    List<Map<String, Object>> getOptimizeOffsetsInfo(String processId);
    int deleteOptimizeOffcut(String projectNumber);
}
north-glass-erp/src/main/java/com/example/erp/service/pp/GlassOptimizeService.java
@@ -355,6 +355,85 @@
        return map;
    }
    public Object getOptimizeInfoSv(String processId) {
        // 获取布局信息
        List<Map<String, Object>> layouts = glassOptimizeMapper.getOptimizeLayoutsInfo(processId);
        // 获取玻璃明细信息
        List<Map<String, Object>> glassDetails = glassOptimizeMapper.getOptimizeDetailsInfo(processId);
        // 获取余料信息
        List<Map<String, Object>> offsets = glassOptimizeMapper.getOptimizeOffsetsInfo(processId);
        // 将玻璃明细和余料合并到一个列表中
        List<Map<String, Object>> allDetails = new ArrayList<>();
        if (glassDetails != null) {
            allDetails.addAll(glassDetails);
        }
        if (offsets != null) {
            allDetails.addAll(offsets);
        }
        // 按照stockId将明细分组并添加到对应的布局中
        if (layouts != null && !layouts.isEmpty()) {
            for (Map<String, Object> layout : layouts) {
                Object stockIdObj = layout.get("stockId");
                if (stockIdObj != null) {
                    Integer stockId = null;
                    if (stockIdObj instanceof Number) {
                        stockId = ((Number) stockIdObj).intValue();
                    } else {
                        try {
                            stockId = Integer.valueOf(stockIdObj.toString());
                        } catch (NumberFormatException e) {
                            // 如果无法转换为数字,则跳过该布局
                            continue;
                        }
                    }
                    List<Map<String, Object>> matchedDetails = new ArrayList<>();
                    for (Map<String, Object> detail : allDetails) {
                        Object layoutIdObj = detail.get("layoutId");
                        Object stockSortObj = detail.get("stockSort");
                        Integer detailStockId = null;
                        if (layoutIdObj != null) {
                            if (layoutIdObj instanceof Number) {
                                detailStockId = ((Number) layoutIdObj).intValue();
                            } else {
                                try {
                                    detailStockId = Integer.valueOf(layoutIdObj.toString());
                                } catch (NumberFormatException e) {
                                    // 跳过无效的layoutId
                                    continue;
                                }
                            }
                        } else if (stockSortObj != null) {
                            if (stockSortObj instanceof Number) {
                                detailStockId = ((Number) stockSortObj).intValue();
                            } else {
                                try {
                                    detailStockId = Integer.valueOf(stockSortObj.toString());
                                } catch (NumberFormatException e) {
                                    // 跳过无效的stockSort
                                    continue;
                                }
                            }
                        }
                        // 如果detail的stockId与layout的stockId匹配,则添加到匹配列表中
                        if (detailStockId != null && detailStockId.equals(stockId)) {
                            matchedDetails.add(detail);
                        }
                    }
                    // 将匹配的明细添加到布局的glassDetails字段中
                    layout.put("glassDetails", matchedDetails);
                }
            }
        }
//        Map<String, Object> result = new HashMap<>();
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("layouts", layouts);
        result.put("optimizeUse", glassOptimizeMapper.materialStoreOptimizeUse(processId));
        return result;
    }
    //工程信息
    public Map<String, Object> projectInfoSv(String projectNo,String username) {
        Map<String, Object> stringObjectMap = glassOptimizeMapper.selectProjectCount(projectNo);
@@ -496,6 +575,7 @@
            else if(code==2){
                glassOptimizeMapper.deleteOptimizeDetail(projectNumber);
                glassOptimizeMapper.deleteOptimizeLayout(projectNumber);
                glassOptimizeMapper.deleteOptimizeOffcut(projectNumber);
                glassOptimizeMapper.deleteOptimizeProjectFile(projectNumber);
                glassOptimizeMapper.updateOptimizeUse(projectNumber);
                glassOptimizeMapper.updateProjectOptimizeStateMp(projectNumber, states);
@@ -993,4 +1073,5 @@
        return saveState;
    }
}
north-glass-erp/src/main/resources/mapper/pp/FolwCard.xml
@@ -1255,6 +1255,8 @@
               fc.order_number,
               ogd.technology_number,
               ogd.glass_address,
               ogd.child_width,
               ogd.child_height,
               pl.patch_num,
               pl.patch_area,
               pl.responsible_team,
@@ -1268,7 +1270,8 @@
               fc.print_status,
               pl.reporting_work_id,
               JSON_UNQUOTE(JSON_EXTRACT(od.other_columns, '$.S01'))                AS glassNumber,
               pl.patch_id
               pl.patch_id,
               date(pl.create_time) as create_time
        from flow_card as fc
                 left join sd.order_glass_detail as ogd
north-glass-erp/src/main/resources/mapper/pp/GlassOptimize.xml
@@ -1224,8 +1224,8 @@
            order_sort,
            stock_id,
            polys_id,
            o_width,
            o_height,
            p_width,
            p_height,
            width,
            height,
            x_axis,
@@ -1287,6 +1287,7 @@
            down_trim,
            left_trim,
            right_trim,
            count,
            glass_count,
            glass_area,
            create_time
@@ -1301,7 +1302,8 @@
            #{glass.downTrim},
            #{glass.leftTrim},
            #{glass.rightTrim},
            #{glass.glassCount},
            #{glass.count},
            #{glass.glassQuantity},
            #{glass.glassArea},
            now()
            );
@@ -1659,6 +1661,13 @@
        delete from pp.other_flow_card
        where project_no = #{projectNumber}
    </delete>
    <delete id="deleteOptimizeOffcut">
        DELETE
        FROM
            pp.optimize_offcut
        WHERE
            project_no = #{projectNumber}
    </delete>
    <select id="selectOptimizeProject">
@@ -1783,6 +1792,65 @@
        where
            project_no = #{projectId}
    </select>
    <select id="getOptimizeLayoutsInfo" resultType="java.util.Map">
        SELECT
            width,
            height,
            stock_id AS stockId,
            stock_code AS stockCode,
            usage_rate AS usageRate,
            up_trim AS upTrim,
            down_trim AS downTrim,
            left_trim AS leftTrim,
            right_trim AS rightTrim,
            count AS quantity,
            glass_count AS glassQuantity
        FROM
            pp.optimize_layout
        where
            project_no = #{projectId}
    </select>
    <select id="getOptimizeDetailsInfo" resultType="java.util.Map">
        SELECT
            0 As isRemain,
            width AS realWidth,
            height AS realHeight,
            p_width AS width,
            p_height AS height,
            process_id AS processId,
            layer,
            total_layer AS totalLayer,
            order_sort As orderSort,
            stock_id AS layoutId,
            stock_number AS glassSort,
            x_axis AS x,
            y_axis AS y,
            mark_icon AS markIcon,
            isRotate,
            rack_no As rackNo
        FROM
            pp.optimize_detail
        WHERE
            project_no = #{projectId}
    </select>
    <select id="getOptimizeOffsetsInfo" resultType="java.util.Map">
        SELECT
            1 AS isRemain,
            0 AS isRotate,
            width AS realWidth,
            height AS realHeight,
            width AS width,
            height AS height,
            stock_id AS stockSort,
            x_axis AS x,
            y_axis AS y,
            model AS glassType,
            thickness AS glassThickness
        FROM
            pp.optimize_offcut
        WHERE
            project_no = #{projectId}
    </select>
</mapper>
north-glass-erp/src/main/resources/mapper/pp/ReportingWork.xml
@@ -429,6 +429,7 @@
                0,
                ifnull(a.completed_quantity+a.breakage_quantity,0)) as 'quantity', -- 可报工数
            ifnull(a.completed_quantity,0) as 'completedQuantity', -- 完工数
            ifnull(a.completed_quantity,0) as 'completedQuantityComputed', -- 完工数
            ifnull(a.breakage_quantity,0) as 'breakageQuantity', -- 破损数
            ifnull(f.completed_quantity,0) as thisQuantitySum ,-- 本工序完工和
            if(c.quantity-f.completed_quantity = 0 ,true,false) as saveFlag,