diff --git a/src/main/java/com/heai/modules/pms/controller/QcController.java b/src/main/java/com/heai/modules/pms/controller/QcController.java index 7409e9a..399053f 100644 --- a/src/main/java/com/heai/modules/pms/controller/QcController.java +++ b/src/main/java/com/heai/modules/pms/controller/QcController.java @@ -873,6 +873,24 @@ public class QcController { return R.ok(); } + @PostMapping("/uploadPartAttrExcel") + public R uploadPartAttrExcel(@RequestParam(value = "file") MultipartFile file, @ModelAttribute GetParamInData data){ + qcService.uploadPartAttrExcel(file, data); + return R.ok(); + } + + @PostMapping("/uploadPartTemplateExcel") + public R uploadPartTemplateExcel(@RequestParam(value = "file") MultipartFile file, @ModelAttribute GetParamInData data){ + qcService.uploadPartTemplateExcel(file, data); + return R.ok(); + } + + @PostMapping("/uploadPartStandardExcel") + public R uploadPartStandardExcel(@RequestParam(value = "file") MultipartFile file, @ModelAttribute GetParamInData data){ + qcService.uploadPartStandardExcel(file, data); + return R.ok(); + } + // ======================= IPQC 巡检特殊配置(按工序) ======================= @PostMapping("/getPatrolConfigList") diff --git a/src/main/java/com/heai/modules/pms/mapper/QcMapper.java b/src/main/java/com/heai/modules/pms/mapper/QcMapper.java index 4facbc7..ee51d14 100644 --- a/src/main/java/com/heai/modules/pms/mapper/QcMapper.java +++ b/src/main/java/com/heai/modules/pms/mapper/QcMapper.java @@ -121,6 +121,8 @@ public interface QcMapper { QcItemData selectQcItemByNo(@Param("site") String site, @Param("itemNo") String itemNo); + QcFAIRecordData selectPartByExactNo(@Param("site") String site, @Param("partNo") String partNo); + QcTemplateData selectDetail(QcTemplateData data); void saveItemDetailed(QcTemplateData data); @@ -189,6 +191,8 @@ public interface QcMapper { void savePartAttributeDetails(QcTemplateData data); + void updatePartAttributeInspectionMethod(QcTemplateData data); + List getTemplateList(QcTemplateData data); List getPartTemplateList(QcTemplateData data); diff --git a/src/main/java/com/heai/modules/pms/service/Impl/QcServiceImpl.java b/src/main/java/com/heai/modules/pms/service/Impl/QcServiceImpl.java index 5658ee8..daff7ff 100644 --- a/src/main/java/com/heai/modules/pms/service/Impl/QcServiceImpl.java +++ b/src/main/java/com/heai/modules/pms/service/Impl/QcServiceImpl.java @@ -1052,7 +1052,7 @@ public class QcServiceImpl implements QcService { } String pairKey = templateId + "||" + itemNo; if (!excelKeys.add(pairKey)) { - throw new RuntimeException("同一模板下检验项目重复:" + itemNo); + throw new RuntimeException("Excel中检验模板【" + templateId + "】的检验项目【" + itemNo + "】重复"); } QcTemplateData template = templateCache.get(templateId); if (template == null) { @@ -1079,6 +1079,14 @@ public class QcServiceImpl implements QcService { && !template.getInspectionTypeNo().equals(item.getInspectionTypeNo())) { throw new RuntimeException("检验项目【" + itemNo + "】与模板检验类型不匹配"); } + QcTemplateData existQuery = new QcTemplateData(); + existQuery.setSite(StringUtils.defaultIfBlank(template.getSite(), site)); + existQuery.setBuNo(StringUtils.defaultIfBlank(template.getBuNo(), buNo)); + existQuery.setTemplateId(template.getTemplateId()); + existQuery.setItemNo(item.getItemNo()); + if (qcMapper.selectItemDetails(existQuery) != null) { + throw new RuntimeException("检验模板【" + template.getTemplateId() + "】下检验项目【" + item.getItemNo() + "】已存在"); + } String excelDefault = QcExcelImportHelper.getString(row, headers, "标准值"); BigDecimal excelMax = QcExcelImportHelper.getDecimal(row, headers, "最大值"); BigDecimal excelMin = QcExcelImportHelper.getDecimal(row, headers, "最小值"); @@ -1102,7 +1110,10 @@ public class QcServiceImpl implements QcService { } Integer nextOrder = orderByTemplate.get(templateId); if (nextOrder == null) { - nextOrder = 1; + nextOrder = qcMapper.getQCDetailOrderId(detail); + if (nextOrder == null) { + nextOrder = 1; + } } detail.setOrderId(nextOrder); orderByTemplate.put(templateId, nextOrder + 1); @@ -1122,11 +1133,9 @@ public class QcServiceImpl implements QcService { if (!errors.isEmpty()) { throw new RuntimeException("导入失败:
" + String.join("
", errors)); } - Set clearedTemplates = new HashSet<>(); for (QcTemplateData detail : toSave) { - String clearKey = detail.getSite() + "||" + detail.getBuNo() + "||" + detail.getTemplateId(); - if (clearedTemplates.add(clearKey)) { - qcMapper.delTemplateItem(detail); + if (qcMapper.selectItemDetails(detail) != null) { + throw new RuntimeException("检验模板【" + detail.getTemplateId() + "】下检验项目【" + detail.getItemNo() + "】已存在"); } qcMapper.addItemDetails(detail); } @@ -1876,6 +1885,484 @@ public class QcServiceImpl implements QcService { } + /** + * 物料属性导入(对应新增) + **/ + @Override + @Transactional + public void uploadPartAttrExcel(MultipartFile file, GetParamInData paramData) { + String site = QcExcelImportHelper.resolveSite(paramData.getSite()); + String buNo = QcExcelImportHelper.resolveBuNo(); + List errors = new ArrayList<>(); + List toSave = new ArrayList<>(); + Set partNos = new HashSet<>(); + try (Workbook workbook = QcExcelImportHelper.openWorkbook(file)) { + Sheet sheet = QcExcelImportHelper.getDataSheet(workbook, QcExcelImportHelper.FLAG_PART_ATTR); + Map headers = QcExcelImportHelper.readHeaderIndex(sheet.getRow(0)); + int lastRow = sheet.getLastRowNum(); + for (int r = 1; r <= lastRow; r++) { + Row row = sheet.getRow(r); + if (QcExcelImportHelper.isBlankRow(row, headers)) { + continue; + } + int excelRow = r + 1; + try { + String partNo = QcExcelImportHelper.getString(row, headers, "物料编码"); + if (StringUtils.isBlank(partNo)) { + throw new RuntimeException("物料编码不能为空"); + } + if (!partNos.add(partNo)) { + throw new RuntimeException("物料编码重复:" + partNo); + } + QcFAIRecordData part = qcMapper.selectPartByExactNo(site, partNo); + if (part == null) { + throw new RuntimeException("物料不存在:" + partNo); + } + QcPartAttributeData task = new QcPartAttributeData(); + task.setSite(site); + task.setBuNo(buNo); + task.setPartNo(part.getPartNo()); + task.setPartDesc(part.getPartDesc()); + task.setAttributeType("A"); + task.setCreateBy(paramData.getCreateBy()); + task.setUpdateBy(paramData.getCreateBy()); + task.setDefaultValue(blankToNull(QcExcelImportHelper.getString(row, headers, "默认值"))); + task.setStandardValue(blankToNull(QcExcelImportHelper.getString(row, headers, "标准值"))); + task.setMaxValue(blankToNull(QcExcelImportHelper.getString(row, headers, "上限值"))); + task.setMinValue(blankToNull(QcExcelImportHelper.getString(row, headers, "下限值"))); + task.setFirstIPQCPatrolTime(QcExcelImportHelper.getDecimal(row, headers, "首次巡检时长(h)", "首次巡检时长")); + task.setLastIPQCPatrolTime(QcExcelImportHelper.getDecimal(row, headers, "下次巡检时长(h)", "下次巡检时长")); + task.setCycleIPQCPatrolTime(QcExcelImportHelper.getDecimal(row, headers, "累计巡检时长(h)", "累计巡检时长")); + task.setIqcExempt(ynOrDefaultN(QcExcelImportHelper.getString(row, headers, "IQC检验"))); + task.setIpqcExempt(ynOrDefaultN(QcExcelImportHelper.getString(row, headers, "IPQC检验"))); + task.setOqcExempt(ynOrDefaultN(QcExcelImportHelper.getString(row, headers, "OQC检验"))); + task.setFqcExempt(ynOrDefaultN(QcExcelImportHelper.getString(row, headers, "FQC检验"))); + task.setSqcExempt(ynOrDefaultN(QcExcelImportHelper.getString(row, headers, "SQC检验"))); + task.setFaiExempt("N"); + task.setPqcExempt("N"); + task.setExemptInspection("N"); + task.setAttributeRemark(blankToNull(QcExcelImportHelper.getString(row, headers, "备注"))); + if (qcMapper.selectPartAttributeByNo(task) != null) { + throw new RuntimeException("该物料属性已存在:" + partNo); + } + toSave.add(task); + } catch (RuntimeException e) { + errors.add("第" + excelRow + "行:" + e.getMessage()); + } + } + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException("导入失败:" + e.getMessage()); + } + assertImportRows(toSave, errors); + for (QcPartAttributeData task : toSave) { + qcPartAttributeSave(task); + } + } + + /** + * 物料检验模板导入(对应检验模板清单) + **/ + @Override + @Transactional + public void uploadPartTemplateExcel(MultipartFile file, GetParamInData paramData) { + String site = QcExcelImportHelper.resolveSite(paramData.getSite()); + String buNo = QcExcelImportHelper.resolveBuNo(); + Map typeNameMap = new HashMap<>(); + for (QcInspectionTypeData type : loadInspectionTypes(site)) { + if (type != null && StringUtils.isNotBlank(type.getInspectionTypeNo())) { + typeNameMap.put(type.getInspectionTypeNo(), type.getInspectionTypeName()); + } + } + Set operations = loadOperationDescs(); + Set resources = loadResourceIds(site); + Map suppliers = loadSupplierKeys(site); + Map customers = loadCustomerKeys(site); + List programmes = loadSamplingProgrammes(site); + List levels = loadSamplingLevels(site); + List errors = new ArrayList<>(); + List toSave = new ArrayList<>(); + Set excelKeys = new HashSet<>(); + try (Workbook workbook = QcExcelImportHelper.openWorkbook(file)) { + Sheet sheet = QcExcelImportHelper.getDataSheet(workbook, QcExcelImportHelper.FLAG_PART_TEMPLATE); + Map headers = QcExcelImportHelper.readHeaderIndex(sheet.getRow(0)); + int lastRow = sheet.getLastRowNum(); + for (int r = 1; r <= lastRow; r++) { + Row row = sheet.getRow(r); + if (QcExcelImportHelper.isBlankRow(row, headers)) { + continue; + } + int excelRow = r + 1; + try { + String partNo = QcExcelImportHelper.getString(row, headers, "物料编码"); + if (StringUtils.isBlank(partNo)) { + throw new RuntimeException("物料编码不能为空"); + } + String templateId = QcExcelImportHelper.getString(row, headers, "检验模板编码"); + if (StringUtils.isBlank(templateId)) { + throw new RuntimeException("检验模板编码不能为空"); + } + QcPartAttributeData partQuery = new QcPartAttributeData(); + partQuery.setSite(site); + partQuery.setBuNo(buNo); + partQuery.setPartNo(partNo); + partQuery.setAttributeType("A"); + if (qcMapper.selectPartAttributeByNo(partQuery) == null) { + throw new RuntimeException("物料属性不存在,请先导入物料属性:" + partNo); + } + QcTemplateData templateQuery = new QcTemplateData(); + templateQuery.setSite(site); + templateQuery.setBuNo(buNo); + templateQuery.setTemplateId(templateId); + QcTemplateData template = qcMapper.selectTemplateData(templateQuery); + if (template == null) { + throw new RuntimeException("检验模板不存在:" + templateId); + } + String typeNo = template.getInspectionTypeNo(); + String operation = blankToNull(QcExcelImportHelper.getString(row, headers, "工序")); + String resourceId = blankToNull(QcExcelImportHelper.getString(row, headers, "机台")); + String supplierInput = QcExcelImportHelper.getString(row, headers, "供应商"); + String customerInput = QcExcelImportHelper.getString(row, headers, "客户"); + String method = resolvePartInspectionMethod(typeNo, typeNameMap.get(typeNo), + QcExcelImportHelper.getString(row, headers, "检验方式")); + QcTemplateData detail = new QcTemplateData(); + detail.setSite(site); + detail.setBuNo(buNo); + detail.setAttributeNo(partNo); + detail.setAttributeType("A"); + detail.setTemplateId(template.getTemplateId()); + detail.setInspectionTypeNo(typeNo); + detail.setUpdateBy(paramData.getCreateBy()); + detail.setIpqcInspectionMethod(method); + String levelInput = QcExcelImportHelper.getString(row, headers, "检验水平编码"); + String programmeInput = QcExcelImportHelper.getString(row, headers, "抽样方案编码"); + detail.setSamplingLevelNo(StringUtils.isNotBlank(levelInput) + ? resolveSamplingLevelNo(levelInput, levels) : template.getSamplingLevelNo()); + detail.setSamplingProgrammeNo(StringUtils.isNotBlank(programmeInput) + ? resolveSamplingProgrammeNo(programmeInput, programmes) : template.getSamplingProgrammeNo()); + BigDecimal cycle = QcExcelImportHelper.getDecimal(row, headers, "检验周期(h)", "检验周期"); + BigDecimal aql = QcExcelImportHelper.getDecimal(row, headers, "AQL"); + BigDecimal ac = QcExcelImportHelper.getDecimal(row, headers, "AC"); + BigDecimal re = QcExcelImportHelper.getDecimal(row, headers, "RE"); + detail.setInspectionCycle(cycle != null ? cycle : template.getInspectionCycle()); + detail.setAql(aql != null ? aql : template.getAql()); + detail.setAc(ac != null ? ac : template.getAc()); + detail.setRe(re != null ? re : template.getRe()); + if (needsOperationAndResource(typeNo)) { + if (StringUtils.isNotBlank(supplierInput) || StringUtils.isNotBlank(customerInput)) { + throw new RuntimeException("当前检验类型只需填写工序和机台"); + } + if (StringUtils.isNotBlank(resourceId) && StringUtils.isBlank(operation)) { + throw new RuntimeException("填写机台时必须填写工序"); + } + if (StringUtils.isNotBlank(operation) && !operations.contains(operation)) { + throw new RuntimeException("工序不存在:" + operation); + } + if (StringUtils.isNotBlank(resourceId) && !resources.contains(resourceId)) { + throw new RuntimeException("机台不存在:" + resourceId); + } + detail.setOperation(operation); + detail.setResourceID(resourceId); + if (!qcMapper.getPA(detail).isEmpty()) { + if (StringUtils.isBlank(operation) && StringUtils.isBlank(resourceId)) { + throw new RuntimeException("未填写工序和机台的模板已存在"); + } + if (StringUtils.isBlank(resourceId)) { + throw new RuntimeException("工序已存在:" + operation); + } + throw new RuntimeException("工序【" + operation + "】和机台【" + resourceId + "】的组合已存在"); + } + } else if ("105".equals(typeNo)) { + if (StringUtils.isNotBlank(operation) || StringUtils.isNotBlank(resourceId) || StringUtils.isNotBlank(customerInput)) { + throw new RuntimeException("IQC只需填写供应商"); + } + String supplierId = resolveMasterId(supplierInput, suppliers, "供应商"); + detail.setManufacturerID(supplierId); + if (!qcMapper.getPA2(detail).isEmpty()) { + throw new RuntimeException(StringUtils.isBlank(supplierId) ? "未填写供应商的模板已存在" : "供应商已存在:" + supplierInput); + } + } else if ("110".equals(typeNo)) { + if (StringUtils.isNotBlank(operation) || StringUtils.isNotBlank(resourceId) || StringUtils.isNotBlank(supplierInput)) { + throw new RuntimeException("OQC只需填写客户"); + } + String customerId = resolveMasterId(customerInput, customers, "客户"); + if (StringUtils.isBlank(customerId)) { + throw new RuntimeException("客户不能为空"); + } + detail.setCustomerID(customerId); + if (!qcMapper.getPA3(detail).isEmpty()) { + throw new RuntimeException("客户已存在:" + customerInput); + } + } else if (StringUtils.isNotBlank(operation) || StringUtils.isNotBlank(resourceId) + || StringUtils.isNotBlank(supplierInput) || StringUtils.isNotBlank(customerInput)) { + throw new RuntimeException("当前检验类型不需要填写工序、机台、供应商或客户"); + } + String excelKey = partNo + "|" + templateId + "|" + StringUtils.defaultString(detail.getOperation()) + + "|" + StringUtils.defaultString(detail.getResourceID()) + + "|" + StringUtils.defaultString(detail.getManufacturerID()) + + "|" + StringUtils.defaultString(detail.getCustomerID()); + if (!excelKeys.add(excelKey)) { + throw new RuntimeException("Excel中存在重复的模板组合"); + } + toSave.add(detail); + } catch (RuntimeException e) { + errors.add("第" + excelRow + "行:" + e.getMessage()); + } + } + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException("导入失败:" + e.getMessage()); + } + assertImportRows(toSave, errors); + Set syncedTemplateKeys = new HashSet<>(); + for (QcTemplateData detail : toSave) { + savePartAttributeDetailAndSync(detail, syncedTemplateKeys); + if (StringUtils.isNotBlank(detail.getIpqcInspectionMethod())) { + qcMapper.updatePartAttributeInspectionMethod(detail); + } + } + } + + /** + * 物料检验标准导入(qc_part_attr_detailed) + **/ + @Override + @Transactional + public void uploadPartStandardExcel(MultipartFile file, GetParamInData paramData) { + String site = QcExcelImportHelper.resolveSite(paramData.getSite()); + String buNo = QcExcelImportHelper.resolveBuNo(); + List errors = new ArrayList<>(); + List toSave = new ArrayList<>(); + Map orderByPart = new HashMap<>(); + Set excelKeys = new HashSet<>(); + try (Workbook workbook = QcExcelImportHelper.openWorkbook(file)) { + Sheet sheet = QcExcelImportHelper.getDataSheet(workbook, QcExcelImportHelper.FLAG_PART_STANDARD); + Map headers = QcExcelImportHelper.readHeaderIndex(sheet.getRow(0)); + int lastRow = sheet.getLastRowNum(); + for (int r = 1; r <= lastRow; r++) { + Row row = sheet.getRow(r); + if (QcExcelImportHelper.isBlankRow(row, headers)) { + continue; + } + int excelRow = r + 1; + try { + String partNo = QcExcelImportHelper.getString(row, headers, "物料编码"); + if (StringUtils.isBlank(partNo)) { + throw new RuntimeException("物料编码不能为空"); + } + String itemNo = QcExcelImportHelper.getString(row, headers, "检验项目编码"); + if (StringUtils.isBlank(itemNo)) { + throw new RuntimeException("检验项目编码不能为空"); + } + if (!excelKeys.add(partNo + "|" + itemNo)) { + throw new RuntimeException("Excel中物料【" + partNo + "】的检验项目【" + itemNo + "】重复"); + } + QcPartAttributeData partQuery = new QcPartAttributeData(); + partQuery.setSite(site); + partQuery.setBuNo(buNo); + partQuery.setPartNo(partNo); + partQuery.setAttributeType("A"); + if (qcMapper.selectPartAttributeByNo(partQuery) == null) { + throw new RuntimeException("物料属性不存在,请先导入物料属性:" + partNo); + } + QcItemData item = qcMapper.selectQcItemByNo(site, itemNo); + if (item == null) { + throw new RuntimeException("检验项目不存在:" + itemNo); + } + QcTemplateData existQuery = new QcTemplateData(); + existQuery.setSite(site); + existQuery.setBuNo(buNo); + existQuery.setAttributeNo(partNo); + existQuery.setItemNo(item.getItemNo()); + if (qcMapper.selectPartAttrItemDetails(existQuery) != null) { + throw new RuntimeException("物料【" + partNo + "】下检验项目【" + item.getItemNo() + "】已存在"); + } + String excelDefault = QcExcelImportHelper.getString(row, headers, "标准值"); + BigDecimal excelMax = QcExcelImportHelper.getDecimal(row, headers, "最大值"); + BigDecimal excelMin = QcExcelImportHelper.getDecimal(row, headers, "最小值"); + QcTemplateData detail = new QcTemplateData(); + detail.setSite(site); + detail.setBuNo(buNo); + detail.setAttributeNo(partNo); + detail.setAttributeType("A"); + detail.setItemNo(item.getItemNo()); + detail.setInspectionTypeNo(item.getInspectionTypeNo()); + detail.setUpdateBy(paramData.getCreateBy()); + detail.setDefaultValue(StringUtils.isNotBlank(excelDefault) ? excelDefault : item.getDefaultValue()); + if ("T".equals(item.getValueTypeDb())) { + detail.setMaxValue(null); + detail.setMinValue(null); + } else { + detail.setMaxValue(excelMax != null ? excelMax : item.getMaxValue()); + detail.setMinValue(excelMin != null ? excelMin : item.getMinValue()); + if (detail.getMaxValue() != null && detail.getMinValue() != null + && detail.getMaxValue().compareTo(detail.getMinValue()) < 0) { + throw new RuntimeException("最大值不能小于最小值"); + } + } + Integer nextOrder = orderByPart.get(partNo); + if (nextOrder == null) { + nextOrder = qcMapper.getPartAttrDetailedMaxOrderId(detail); + if (nextOrder == null) { + nextOrder = 1; + } + } + detail.setOrderId(nextOrder); + orderByPart.put(partNo, nextOrder + 1); + toSave.add(detail); + } catch (RuntimeException e) { + errors.add("第" + excelRow + "行:" + e.getMessage()); + } + } + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException("导入失败:" + e.getMessage()); + } + assertImportRows(toSave, errors); + Set updatedParts = new HashSet<>(); + for (QcTemplateData detail : toSave) { + if (qcMapper.selectPartAttrItemDetails(detail) != null) { + throw new RuntimeException("物料【" + detail.getAttributeNo() + "】下检验项目【" + detail.getItemNo() + "】已存在"); + } + qcMapper.insertPartAttrDetailed(detail); + if (updatedParts.add(detail.getAttributeNo())) { + qcMapper.updatePartAttributeTime(detail); + } + } + } + + private void assertImportRows(List toSave, List errors) { + if (toSave.isEmpty() && errors.isEmpty()) { + throw new RuntimeException("没有可导入的数据,请检查Excel内容"); + } + if (!errors.isEmpty()) { + throw new RuntimeException("导入失败:
" + String.join("
", errors)); + } + } + + private String ynOrDefaultN(String value) { + if (StringUtils.isBlank(value)) { + return "N"; + } + return QcExcelImportHelper.resolveYn(value); + } + + private boolean needsOperationAndResource(String typeNo) { + return "101".equals(typeNo) || "102".equals(typeNo) || "103".equals(typeNo) + || "104".equals(typeNo) || "106".equals(typeNo) || "107".equals(typeNo); + } + + private String resolvePartInspectionMethod(String typeNo, String typeName, String value) { + boolean ipqc = "101".equals(typeNo) || (typeName != null && typeName.toUpperCase().contains("IPQC")); + boolean iqc = "105".equals(typeNo) || (typeName != null && typeName.toUpperCase().contains("IQC")); + if (!ipqc && !iqc) { + if (StringUtils.isNotBlank(value)) { + throw new RuntimeException("当前检验类型不需要填写检验方式"); + } + return null; + } + if (StringUtils.isBlank(value)) { + throw new RuntimeException("检验方式不能为空"); + } + String input = value.trim(); + List options = iqc ? QcExcelImportHelper.iqcInspectionMethods() : QcExcelImportHelper.ipqcInspectionMethods(); + if (!options.contains(input)) { + throw new RuntimeException("检验方式不合法:" + value); + } + return input; + } + + private Set loadOperationDescs() { + Set set = new HashSet<>(); + List list = qcMapper.getOperationDescList(new QcPartAttributeData()); + if (list != null) { + for (QcPartAttributeData row : list) { + if (row != null && StringUtils.isNotBlank(row.getOperationDesc())) { + set.add(row.getOperationDesc().trim()); + } + } + } + return set; + } + + private Set loadResourceIds(String site) { + Set set = new HashSet<>(); + QcFAIRecordData query = new QcFAIRecordData(); + query.setSite(site); + List list = qcMapper.getAllResourceList(query); + if (list != null) { + for (QcFAIRecordData row : list) { + if (row != null && StringUtils.isNotBlank(row.getResourceId())) { + set.add(row.getResourceId().trim()); + } + } + } + return set; + } + + private Map loadSupplierKeys(String site) { + QcPartAttributeData query = new QcPartAttributeData(); + query.setSite(site); + return toMasterKeyMap(qcMapper.getManufacturerList(query), true); + } + + private Map loadCustomerKeys(String site) { + QcPartAttributeData query = new QcPartAttributeData(); + query.setSite(site); + return toMasterKeyMap(qcMapper.getCustomerList(query), false); + } + + private Map toMasterKeyMap(List list, boolean supplier) { + Map map = new HashMap<>(); + if (list == null) { + return map; + } + for (QcPartAttributeData row : list) { + if (row == null) { + continue; + } + String id = supplier ? row.getManufacturerID() : row.getCustomerID(); + String name = supplier ? row.getManufacturerName() : row.getCustomerName(); + if (StringUtils.isBlank(id)) { + continue; + } + map.put("ID:" + id.trim(), id.trim()); + if (StringUtils.isNotBlank(name)) { + String nameKey = "NAME:" + name.trim(); + String exists = map.get(nameKey); + if (exists == null) { + map.put(nameKey, id.trim()); + } else if (!exists.equals(id.trim())) { + map.put(nameKey, ""); + } + } + } + return map; + } + + private String resolveMasterId(String input, Map keys, String label) { + if (StringUtils.isBlank(input)) { + return null; + } + String value = input.trim(); + String byId = keys.get("ID:" + value); + if (StringUtils.isNotBlank(byId)) { + return byId; + } + String byName = keys.get("NAME:" + value); + if ("".equals(byName)) { + throw new RuntimeException(label + "名称不唯一,请填写编码:" + value); + } + if (StringUtils.isNotBlank(byName)) { + return byName; + } + throw new RuntimeException(label + "不存在:" + value); + } + + // ======================= 类别属性设置维护 ======================= /** diff --git a/src/main/java/com/heai/modules/pms/service/QcService.java b/src/main/java/com/heai/modules/pms/service/QcService.java index 1dff9e5..b78b765 100644 --- a/src/main/java/com/heai/modules/pms/service/QcService.java +++ b/src/main/java/com/heai/modules/pms/service/QcService.java @@ -181,6 +181,12 @@ public interface QcService { void uploadPartAttributeExcel(MultipartFile file, GetParamInData data); + void uploadPartAttrExcel(MultipartFile file, GetParamInData data); + + void uploadPartTemplateExcel(MultipartFile file, GetParamInData data); + + void uploadPartStandardExcel(MultipartFile file, GetParamInData data); + void uploadFamilyAttributeExcel(MultipartFile file, GetParamInData data); PageUtils qcFAIInspectionSearch(QcFAIRecordData data); diff --git a/src/main/java/com/heai/modules/pms/util/QcExcelImportHelper.java b/src/main/java/com/heai/modules/pms/util/QcExcelImportHelper.java index a008606..14aaabc 100644 --- a/src/main/java/com/heai/modules/pms/util/QcExcelImportHelper.java +++ b/src/main/java/com/heai/modules/pms/util/QcExcelImportHelper.java @@ -44,6 +44,9 @@ public final class QcExcelImportHelper { public static final String FLAG_ITEM = "item"; public static final String FLAG_TEMPLATE = "template"; public static final String FLAG_TEMPLATE_ITEM = "templateItem"; + public static final String FLAG_PART_ATTR = "partAttr"; + public static final String FLAG_PART_TEMPLATE = "partTemplate"; + public static final String FLAG_PART_STANDARD = "partStandard"; public static final String DEFAULT_BU_NO = "*"; private static final int DATA_ROW_END = 1000; @@ -65,6 +68,7 @@ public final class QcExcelImportHelper { public static class TemplateOptions { private List inspectionTypeNames = new ArrayList<>(); + private List inspectionMethods = new ArrayList<>(); public List getInspectionTypeNames() { return inspectionTypeNames; @@ -73,6 +77,22 @@ public final class QcExcelImportHelper { public void setInspectionTypeNames(List inspectionTypeNames) { this.inspectionTypeNames = inspectionTypeNames == null ? new ArrayList() : inspectionTypeNames; } + + public List getInspectionMethods() { + return inspectionMethods; + } + + public void setInspectionMethods(List inspectionMethods) { + this.inspectionMethods = inspectionMethods == null ? new ArrayList() : inspectionMethods; + } + } + + public static List ipqcInspectionMethods() { + return Arrays.asList("首件检", "自检", "巡检", "末件检"); + } + + public static List iqcInspectionMethods() { + return Arrays.asList("材料进货检验", "刀模进货检验-外观", "刀模进货检验-上机", "刀模维修检验-外观", "刀模维修检验-上机"); } private QcExcelImportHelper() { @@ -102,6 +122,25 @@ public final class QcExcelImportHelper { return new String[]{"*检验模板编码", "*检验项目编码", "标准值", "最大值", "最小值"}; } + public static String[] partAttrHeaders() { + return new String[]{ + "*物料编码", "默认值", "标准值", "上限值", "下限值", + "首次巡检时长(h)", "下次巡检时长(h)", "累计巡检时长(h)", + "IQC检验", "IPQC检验", "OQC检验", "FQC检验", "SQC检验", "备注" + }; + } + + public static String[] partTemplateHeaders() { + return new String[]{ + "*物料编码", "*检验模板编码", "检验方式", "工序", "机台", "供应商", "客户", + "检验水平编码", "检验周期(h)", "抽样方案编码", "AQL", "AC", "RE" + }; + } + + public static String[] partStandardHeaders() { + return new String[]{"*物料编码", "*检验项目编码", "标准值", "最大值", "最小值"}; + } + public static String dataSheetName(String flag) { if (FLAG_METHOD.equals(flag)) { return "检验方法"; @@ -115,6 +154,15 @@ public final class QcExcelImportHelper { if (FLAG_TEMPLATE_ITEM.equals(flag)) { return "模板检验项目"; } + if (FLAG_PART_ATTR.equals(flag)) { + return "物料属性"; + } + if (FLAG_PART_TEMPLATE.equals(flag)) { + return "物料检验模板"; + } + if (FLAG_PART_STANDARD.equals(flag)) { + return "物料检验标准"; + } throw new RuntimeException("不支持的导入模板类型"); } @@ -158,7 +206,21 @@ public final class QcExcelImportHelper { note = "带*列为必填。检验类型、检验值类型、需上传图片请用下拉选择。方法编码、抽样方案编码、检验水平编码请按系统中已有编码手填。填写抽样方案时须同时填写检验水平。项目编码由系统自动生成。"; } else if (FLAG_TEMPLATE_ITEM.equals(flag)) { headers = templateItemHeaders(); - note = "带*列为必填。同一模板在本次Excel中的行将覆盖该模板原有检验项目清单,序号按Excel顺序从1开始。标准值、最大值、最小值不填则取检验项目上的值;填写则以Excel为准。不导入判定标准。"; + note = "带*列为必填。只新增,不覆盖原有检验项目。同一模板下检验项目不能与已有清单或本次Excel重复,重复则整批不导入。序号接在原有清单之后,按Excel顺序排列。标准值、最大值、最小值不填则取检验项目上的值;填写则以Excel为准。不导入判定标准。"; + needFixedDropdown = false; + } else if (FLAG_PART_ATTR.equals(flag)) { + headers = partAttrHeaders(); + note = "带*列为必填。物料名称按物料编码自动带出。IQC检验、IPQC检验、OQC检验、FQC检验、SQC检验请选择 是 或 否,不填按否。工厂取当前用户默认工厂。"; + } else if (FLAG_PART_TEMPLATE.equals(flag)) { + headers = partTemplateHeaders(); + note = "带*列为必填。工序、机台、供应商可以不填;填写机台时必须同时填写工序。OQC需填写客户。检验水平编码、检验周期、抽样方案编码、AQL、AC、RE不填则取检验模板上的值,填写则以Excel为准。检验水平、抽样方案须为系统中已有编码或名称。检验方式在IPQC、IQC时必填。"; + List methods = new ArrayList<>(); + methods.addAll(ipqcInspectionMethods()); + methods.addAll(iqcInspectionMethods()); + options.setInspectionMethods(methods); + } else if (FLAG_PART_STANDARD.equals(flag)) { + headers = partStandardHeaders(); + note = "带*列为必填。只新增,不覆盖原有检验标准。同一物料下检验项目不能与已有标准或本次Excel重复,重复则整批不导入。序号接在原有标准之后,按Excel顺序排列。标准值、最大值、最小值不填则取检验项目上的值;填写则以Excel为准。"; needFixedDropdown = false; } else { headers = templateHeaders(); @@ -180,13 +242,19 @@ public final class QcExcelImportHelper { textStyle.setDataFormat(workbook.createDataFormat().getFormat("@")); applyTextColumns(sheet, headers, textStyle, "检验类型", "检验值类型", "方法编码", "抽样方案编码", "检验水平编码", "需上传图片", - "检验模板编码", "检验项目编码", "标准值"); + "检验模板编码", "检验项目编码", "标准值", "物料编码", "检验方式", "工序", "机台", "供应商", "客户"); if (needFixedDropdown) { writeOptionsSheet(workbook, options); addDropdown(sheet, headers, "检验类型", "optInspectionType"); addDropdown(sheet, headers, "检验值类型", "optValueType"); addDropdown(sheet, headers, "需上传图片", "optYn"); + addDropdown(sheet, headers, "IQC检验", "optYn"); + addDropdown(sheet, headers, "IPQC检验", "optYn"); + addDropdown(sheet, headers, "OQC检验", "optYn"); + addDropdown(sheet, headers, "FQC检验", "optYn"); + addDropdown(sheet, headers, "SQC检验", "optYn"); + addDropdown(sheet, headers, "检验方式", "optInspectMethod"); } Sheet noteSheet = workbook.createSheet("填写说明"); @@ -216,6 +284,15 @@ public final class QcExcelImportHelper { if (FLAG_TEMPLATE_ITEM.equals(flag)) { return "模板检验项目导入模板.xlsx"; } + if (FLAG_PART_ATTR.equals(flag)) { + return "物料属性导入模板.xlsx"; + } + if (FLAG_PART_TEMPLATE.equals(flag)) { + return "物料检验模板导入模板.xlsx"; + } + if (FLAG_PART_STANDARD.equals(flag)) { + return "物料检验标准导入模板.xlsx"; + } return "QC导入模板.xlsx"; } @@ -421,19 +498,28 @@ public final class QcExcelImportHelper { private static void writeOptionsSheet(Workbook workbook, TemplateOptions options) { Sheet sheet = workbook.createSheet(OPTIONS_SHEET); - String[] titles = {"检验类型", "检验值类型", "需上传图片"}; + boolean hasMethods = sizeOf(options.getInspectionMethods()) > 0; + String[] titles = hasMethods + ? new String[]{"检验类型", "检验值类型", "需上传图片", "检验方式"} + : new String[]{"检验类型", "检验值类型", "需上传图片"}; Row titleRow = sheet.createRow(0); for (int i = 0; i < titles.length; i++) { titleRow.createCell(i).setCellValue(titles[i]); - sheet.setColumnWidth(i, 18 * 256); + sheet.setColumnWidth(i, 22 * 256); } writeOptionColumn(sheet, 0, options.getInspectionTypeNames()); writeOptionColumn(sheet, 1, Arrays.asList("文本", "数字")); writeOptionColumn(sheet, 2, Arrays.asList("是", "否")); + if (hasMethods) { + writeOptionColumn(sheet, 3, options.getInspectionMethods()); + } createName(workbook, "optInspectionType", 0, sizeOf(options.getInspectionTypeNames())); createName(workbook, "optValueType", 1, 2); createName(workbook, "optYn", 2, 2); + if (hasMethods) { + createName(workbook, "optInspectMethod", 3, sizeOf(options.getInspectionMethods())); + } } private static void writeOptionColumn(Sheet sheet, int col, List values) { diff --git a/src/main/resources/mapper/pms/QcMapper.xml b/src/main/resources/mapper/pms/QcMapper.xml index ebd5a7b..8e01728 100644 --- a/src/main/resources/mapper/pms/QcMapper.xml +++ b/src/main/resources/mapper/pms/QcMapper.xml @@ -160,6 +160,14 @@ WHERE site = #{site} AND ItemNo = #{itemNo} AND ItemType = 'D' + + SELECT @@ -3925,7 +3947,15 @@ attribute_type, manufacturer_id FROM qc_attribute_template - WHERE site = #{site} and bu_no = #{buNo} and attribute_no = #{attributeNo} and attribute_type = #{attributeType} and template_id = #{templateId} and manufacturer_id = #{manufacturerID} + WHERE site = #{site} and bu_no = #{buNo} and attribute_no = #{attributeNo} and attribute_type = #{attributeType} and template_id = #{templateId} + + + AND manufacturer_id = #{manufacturerID} + + + AND (manufacturer_id IS NULL OR manufacturer_id = '') + +