From daea1b9b710263e37d3cf201c00b269cf0a3dc6d Mon Sep 17 00:00:00 2001 From: jiayang yue Date: Tue, 20 May 2025 00:54:03 +0800 Subject: [PATCH] =?UTF-8?q?2025.05.19=20qms=20=E7=89=A9=E6=96=99=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E8=AE=BE=E7=BD=AE=E5=AF=BC=E5=85=A5=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sys/modules/pms/mapper/QcMapper.java | 19 +++ .../pms/service/Impl/QcServiceImpl.java | 136 ++++++++++++------ src/main/resources/mapper/pms/QcMapper.xml | 24 +++- 3 files changed, 134 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/xujie/sys/modules/pms/mapper/QcMapper.java b/src/main/java/com/xujie/sys/modules/pms/mapper/QcMapper.java index b3e575a..49b4e6d 100644 --- a/src/main/java/com/xujie/sys/modules/pms/mapper/QcMapper.java +++ b/src/main/java/com/xujie/sys/modules/pms/mapper/QcMapper.java @@ -9,10 +9,13 @@ import com.xujie.sys.modules.pms.entity.DetailTree; import com.xujie.sys.modules.sys.entity.SysSceneDynamicControlModelEntity; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; +import java.util.Set; + /** * @description: 质量管理持久层 * @author: fengyuan_yang @@ -611,4 +614,20 @@ public interface QcMapper { List getIPQCDetailInfo(@Param("site") String site, @Param("buNo") String buNo, @Param("inspectionNo") String inspectionNo); void updateIPQCRecord(QcFAIRecordData recordData); + + @Select("SELECT attribute_no FROM qc_part_attribute WHERE site = #{site} AND bu_no = #{buNo}") + Set selectAllAttributeNos(String site, String buNo); + + @Select("SELECT template_id,sampling_level_no,inspection_cycle,sampling_programme_no,AQL,AC,RE," + + "site,bu_no " + + "FROM " + + "qc_template" + + " WHERE site = #{site} " + + "AND bu_no = " + + "#{buNo}") + List selectAllTemplateData(String site, String buNo); + + void batchSavePartAttribute(List newAttrs); + + void batchSavePartAttributeDetails(List newDetails); } diff --git a/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java b/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java index 9012824..734fd09 100644 --- a/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java @@ -24,9 +24,12 @@ import com.xujie.sys.modules.pms.util.HttpClientUtil; import com.xujie.sys.modules.pms.util.ResponseData; import com.xujie.sys.modules.report.dao.ProcedureDao; import com.xujie.sys.modules.sys.entity.SysSceneDynamicControlModelEntity; +import javafx.util.Pair; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.DataFormatter; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; @@ -43,6 +46,11 @@ import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import org.apache.poi.xssf.eventusermodel.XSSFReader; +import org.xml.sax.XMLReader; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.xml.sax.SAXException; import javax.mail.internet.MimeMessage; import javax.servlet.ServletOutputStream; @@ -58,6 +66,7 @@ import java.text.DecimalFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; +import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -1452,60 +1461,101 @@ public class QcServiceImpl implements QcService { @Override @Transactional public void uploadPartAttributeExcel(MultipartFile file, GetParamInData paramData) { - try(InputStream is = file.getInputStream(); - XSSFWorkbook workbook = new XSSFWorkbook(is)) { + DataFormatter formatter = new DataFormatter(); + List newAttrs = new ArrayList<>(); + List newDetails = new ArrayList<>(); + + // 1. 预加载:已有 attributeNo 和 模板主数据 + Set existNos = new HashSet<>( + qcMapper.selectAllAttributeNos(paramData.getSite(), paramData.getBuNo()) + ); + Map templateMap = qcMapper.selectAllTemplateData(paramData.getSite(), paramData.getBuNo()) + .stream() + .collect(Collectors.toMap(QcTemplateData::getTemplateId, Function.identity())); + + try (InputStream is = file.getInputStream(); + XSSFWorkbook workbook = new XSSFWorkbook(is)) { XSSFSheet sheet = workbook.getSheetAt(0); - int rows = sheet.getPhysicalNumberOfRows(); + for (int rowIdx = 1; rowIdx <= sheet.getLastRowNum(); rowIdx++) { + XSSFRow row = sheet.getRow(rowIdx); + if (row == null) continue; + + // —— 解析 partNo —— + String partNo = formatter.formatCellValue(row.getCell(0)); + if (partNo == null || partNo.isEmpty()) { + throw new RuntimeException("第 " + (rowIdx+1) + " 行:[物料编码] 不能为空"); + } - // 遍历每一行(从第二行开始) - for (int j = 1; j < rows; j++) { - // 实例化对象 - QcPartAttributeData task = new QcPartAttributeData(); - // 获得该行 - XSSFRow row = sheet.getRow(j); - // 为对象赋值 - task.setSite(paramData.getSite()); - task.setPartNo(row.getCell(0).getRawValue()); - task.setSupplierNo(row.getCell(1).getRawValue()); - task.setAttributeType("A"); - task.setAttributeRemark(row.getCell(2).getStringCellValue()); - task.setCreateBy(paramData.getCreateBy()); - // 查重 - task.setAttributeNo(task.getPartNo()); - QcPartAttributeData partAttributeData = qcMapper.selectPartAttributeByNo(task); - if(partAttributeData != null){ - throw new RuntimeException("该物料属性已存在!"); + // 如果数据库已存在,跳过新增属性,只插入新明细 + boolean isNewAttr = existNos.add(partNo); + if (isNewAttr) { + QcPartAttributeData attr = new QcPartAttributeData(); + attr.setSite(paramData.getSite()); + attr.setBuNo(paramData.getBuNo()); + attr.setAttributeNo(partNo); + attr.setPartNo(partNo); + attr.setSupplierNo(formatter.formatCellValue(row.getCell(1))); + attr.setAttributeType("A"); + attr.setAttributeRemark(formatter.formatCellValue(row.getCell(2))); + attr.setCreateBy(paramData.getCreateBy()); + newAttrs.add(attr); } - // 新增物料属性 - qcMapper.qcPartAttributeSave(task); - QcTemplateData templateData = new QcTemplateData(); - templateData.setSite(task.getSite()); - templateData.setAttributeNo(task.getPartNo()); - // 新增物料属性中的模板 - int cells = row.getLastCellNum(); - for (int i = 1; i <= cells - 3; i++) { - templateData.setTemplateId(row.getCell(2 + i).getRawValue()); - QcTemplateData data = qcMapper.selectTemplateData(templateData); - templateData.setSamplingLevelNo(data.getSamplingLevelNo()); - templateData.setInspectionCycle(data.getInspectionCycle()); - templateData.setSamplingProgrammeNo(data.getSamplingProgrammeNo()); - templateData.setAql(data.getAql()); - templateData.setAc(data.getAc()); - templateData.setRe(data.getRe()); - templateData.setAttributeType(task.getAttributeType()); - // 新增 - qcMapper.savePartAttributeDetails(templateData); + + // —— 解析模板明细列(第 3 列以后)—— + for (int c = 3; c < row.getLastCellNum(); c++) { + String tplId = formatter.formatCellValue(row.getCell(c)); + if (tplId == null || tplId.isEmpty()) continue; + + QcTemplateData master = templateMap.get(tplId); + if (master == null) { + throw new RuntimeException("找不到模板配置:" + tplId); + } + + // 复制主数据字段到明细 + QcTemplateData detail = new QcTemplateData(); + detail.setSite(paramData.getSite()); + detail.setBuNo(paramData.getBuNo()); + detail.setAttributeNo(partNo); + detail.setTemplateId(master.getTemplateId()); + detail.setSamplingLevelNo(master.getSamplingLevelNo()); + detail.setInspectionCycle(master.getInspectionCycle()); + detail.setSamplingProgrammeNo(master.getSamplingProgrammeNo()); + detail.setAql(master.getAql()); + detail.setAc(master.getAc()); + detail.setRe(master.getRe()); + detail.setAttributeType("A"); + newDetails.add(detail); } } } catch (IOException e) { - throw new RuntimeException("Failed to read Excel file.", e); - } catch (DataAccessException e) { - throw new RuntimeException("Database access failed.", e); + throw new RuntimeException("读取 Excel 失败", e); + } + + // 4. 批量写库 + // 批量插入属性 + if (!newAttrs.isEmpty()) { + int attrBatch = 200; // 根据字段数和参数限制设定 + for (int i = 0; i < newAttrs.size(); i += attrBatch) { + int end = Math.min(i + attrBatch, newAttrs.size()); + qcMapper.batchSavePartAttribute(newAttrs.subList(i, end)); + } + } + + // 批量插入明细 + if (!newDetails.isEmpty()) { + int detailBatch = 100; + for (int i = 0; i < newDetails.size(); i += detailBatch) { + int end = Math.min(i + detailBatch, newDetails.size()); + qcMapper.batchSavePartAttributeDetails(newDetails.subList(i, end)); + } } } + + + // ======================= 类别属性设置维护 ======================= /** diff --git a/src/main/resources/mapper/pms/QcMapper.xml b/src/main/resources/mapper/pms/QcMapper.xml index 5b35a42..2deeb7c 100644 --- a/src/main/resources/mapper/pms/QcMapper.xml +++ b/src/main/resources/mapper/pms/QcMapper.xml @@ -972,8 +972,8 @@ qa.site, qa.bu_no, dbo.get_bu_desc(qa.site, qa.bu_no) as buDesc, - p.PartNo as partNo, - dbo.Get_Part_DescSpec(qa.site, p.PartNo) as part_desc, + qa.attribute_no as partNo, + dbo.Get_Part_DescSpec(qa.site, qa.attribute_no) as part_desc, p.FamilyID, p.spec as FamilyName, p.umid, @@ -4203,6 +4203,26 @@ VALUES (#{site}, #{buNo}, #{templateId}, #{itemNo}, #{defaultValue}, #{maxValue,jdbcType=DECIMAL}, #{minValue,jdbcType=DECIMAL}, #{serialNo}) + + INSERT INTO qc_part_attribute (attribute_no, supplier_no, attribute_remark, create_time, create_by, attribute_type, site, exempt_inspection, bu_no) + VALUES + + (#{item.attributeNo}, #{item.supplierNo}, #{item.attributeRemark}, getDate(), #{item.createBy}, #{item.attributeType}, #{item.site}, #{item.exemptInspection}, #{item.buNo}) + + + + INSERT INTO qc_attribute_template + (site, bu_no, attribute_no, template_id, + sampling_level_no, inspection_cycle, + sampling_programme_no, aql, ac, re, attribute_type) + VALUES + + (#{item.site}, #{item.buNo}, #{item.attributeNo}, + #{item.templateId}, #{item.samplingLevelNo}, + #{item.inspectionCycle}, #{item.samplingProgrammeNo}, + #{item.aql}, #{item.ac}, #{item.re}, #{item.attributeType}) + +