| | |
| | | |
| | | // 1. 提取设备信息 |
| | | EamMaintenanceStandard eamMaintenanceStandard = extractDeviceInfo(sheet); |
| | | if (eamMaintenanceStandard == null) { |
| | | if (eamMaintenanceStandard == null || eamMaintenanceStandard.getEquipmentId() == null) { |
| | | return Result.error("设备信息提取失败"); |
| | | } else { |
| | | if (eamMaintenanceStandard.getEquipmentId() == null) { |
| | | return Result.error("设备信息提取失败"); |
| | | } |
| | | } |
| | | |
| | | eamMaintenanceStandard.setStandardName(name); |
| | | |
| | | EamMaintenanceStandard exist = checkDuplicate(eamMaintenanceStandard.getEquipmentId(), eamMaintenanceStandard.getMaintenanceCategory(), MaintenanceStandardStatusEnum.START.name()); |
| | | // 检查重复 |
| | | EamMaintenanceStandard exist = checkDuplicate(eamMaintenanceStandard.getEquipmentId(), |
| | | eamMaintenanceStandard.getMaintenanceCategory(), MaintenanceStandardStatusEnum.START.name()); |
| | | if (exist != null) { |
| | | return Result.error(name + ": 设备标准已存在,不能重复添加"); |
| | | } |
| | | |
| | | eamMaintenanceStandardMapper.insert(eamMaintenanceStandard); |
| | | |
| | | // 2. 提取每日点检项目 |
| | | List<EamMaintenanceStandardDetail> dailyDetails = extractDailyItems(sheet, eamMaintenanceStandard); |
| | | Map<Integer, String> rowErrors = new HashMap<>(); |
| | | |
| | | // 2. 提取每日点检项目(优化空行和结束标记处理) |
| | | List<EamMaintenanceStandardDetail> dailyDetails = extractDailyItems(sheet, eamMaintenanceStandard, rowErrors); |
| | | if (dailyDetails.isEmpty()) { |
| | | return Result.error("未找到每日点检项目"); |
| | | } |
| | | |
| | | // 3. 提取周保养项目 |
| | | List<EamMaintenanceStandardDetail> weeklyDetails = extractWeeklyItems(sheet, eamMaintenanceStandard); |
| | | List<EamMaintenanceStandardDetail> weeklyDetails = extractWeeklyItems(sheet, eamMaintenanceStandard, rowErrors); |
| | | if (weeklyDetails.isEmpty()) { |
| | | return Result.error("未找到周保养项目"); |
| | | } |
| | |
| | | eamMaintenanceStandardDetailService.saveBatch(allDetails); |
| | | } |
| | | |
| | | SysParams sysParams = sysParamsService.getSysPramBySettingKey("maintenance_import_type"); |
| | | |
| | | if (sysParams != null) { |
| | | if (sysParams.getSettingValue().equals("1")) { |
| | | //触发保养流程 |
| | | SysParams sysParams = sysParamsService.getSysPramBySettingKey("maintenance_import_type"); |
| | | if (sysParams != null && sysParams.getSettingValue().equals("1")) { |
| | | eamMaintenanceStandard.setStandardStatus(MaintenanceStandardStatusEnum.WAIT_SUBMIT.name()); |
| | | eamMaintenanceStandardMapper.updateById(eamMaintenanceStandard); |
| | | } |
| | | } else { |
| | | return Result.error("未找到保养流程导入相关配置,请联系管理员"); |
| | | } |
| | |
| | | } |
| | | |
| | | /** |
| | | * 提取每日点检项目 |
| | | */ |
| | | private List<EamMaintenanceStandardDetail> extractDailyItems(Sheet sheet, EamMaintenanceStandard standard) { |
| | | return extractItems(sheet, standard, "点检项目", "完成数据/要求", "DAY_INSPECTION"); |
| | | } |
| | | |
| | | /** |
| | | * 提取周保养项目 |
| | | */ |
| | | private List<EamMaintenanceStandardDetail> extractWeeklyItems(Sheet sheet, EamMaintenanceStandard standard) { |
| | | return extractItems(sheet, standard, "周保养项目", "检查标准", "WEEK_INSPECTION"); |
| | | } |
| | | |
| | | /** |
| | | * 通用项目提取方法 |
| | | */ |
| | | private List<EamMaintenanceStandardDetail> extractItems(Sheet sheet, EamMaintenanceStandard standard, |
| | | String primaryHeader, String secondaryHeader, |
| | | String itemCategory) { |
| | | int[] section = findTableSection(sheet, primaryHeader, secondaryHeader); |
| | | if (section == null) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | List<EamMaintenanceStandardDetail> details = new ArrayList<>(); |
| | | for (int rowIdx = section[0]; rowIdx <= section[1]; rowIdx++) { |
| | | Row row = sheet.getRow(rowIdx); |
| | | if (row == null || isEmptyRow(row)) { |
| | | continue; |
| | | } |
| | | |
| | | // 确保第一列是序号(数字) |
| | | Cell seqCell = row.getCell(0); |
| | | if (seqCell == null || seqCell.getCellType() != CellType.NUMERIC) { |
| | | continue; |
| | | } |
| | | |
| | | // 创建项目详情 |
| | | EamMaintenanceStandardDetail detail = new EamMaintenanceStandardDetail(); |
| | | detail.setStandardId(standard.getId()); |
| | | detail.setItemCode(Integer.parseInt(getCellStringValue(row.getCell(0)))); |
| | | detail.setItemName(getCellStringValue(row.getCell(1))); |
| | | detail.setItemCategory(itemCategory); |
| | | |
| | | // 根据项目类型设置需求字段 |
| | | if ("DAY_INSPECTION".equals(itemCategory)) { |
| | | detail.setItemDemand(getCellStringValue(row.getCell(2))); |
| | | } else if ("WEEK_INSPECTION".equals(itemCategory)) { |
| | | detail.setItemDemand(getCellStringValue(row.getCell(2))); |
| | | } |
| | | |
| | | details.add(detail); |
| | | } |
| | | |
| | | return details; |
| | | } |
| | | |
| | | /** |
| | | * 查找表格区域 |
| | | */ |
| | | private int[] findTableSection(Sheet sheet, String primaryHeader, String secondaryHeader) { |
| | | for (int rowIdx = 0; rowIdx <= sheet.getLastRowNum(); rowIdx++) { |
| | | Row row = sheet.getRow(rowIdx); |
| | | if (row == null) continue; |
| | | |
| | | if (isHeaderRow(row, primaryHeader, secondaryHeader)) { |
| | | int startRow = rowIdx + 1; |
| | | int endRow = findDataEnd(sheet, startRow); |
| | | return new int[]{startRow, endRow}; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 检查是否为表头行 |
| | | */ |
| | | private boolean isHeaderRow(Row row, String header1, String header2) { |
| | | boolean foundHeader1 = false; |
| | | boolean foundHeader2 = false; |
| | | |
| | | for (int colIdx = 0; colIdx < row.getLastCellNum(); colIdx++) { |
| | | Cell cell = row.getCell(colIdx); |
| | | if (cell == null) continue; |
| | | |
| | | String cellValue = getCellStringValue(cell); |
| | | if (cellValue.contains(header1)) foundHeader1 = true; |
| | | if (cellValue.contains(header2)) foundHeader2 = true; |
| | | } |
| | | |
| | | return foundHeader1 && foundHeader2; |
| | | } |
| | | |
| | | /** |
| | | * 查找数据结束位置 |
| | | */ |
| | | private int findDataEnd(Sheet sheet, int startRow) { |
| | | for (int rowIdx = startRow; rowIdx <= sheet.getLastRowNum(); rowIdx++) { |
| | | Row row = sheet.getRow(rowIdx); |
| | | if (row == null) return rowIdx - 1; |
| | | |
| | | // 检查是否结束标志行(如签字行) |
| | | if (isSignatureRow(row)) { |
| | | return rowIdx - 1; |
| | | } |
| | | |
| | | // 检查是否新的表头开始 |
| | | if (isNewHeaderStart(row)) { |
| | | return rowIdx - 1; |
| | | } |
| | | } |
| | | return sheet.getLastRowNum(); |
| | | } |
| | | |
| | | /** |
| | | * 识别签字行特征 |
| | | */ |
| | | private boolean isSignatureRow(Row row) { |
| | | for (int colIdx = 0; colIdx < row.getLastCellNum(); colIdx++) { |
| | | Cell cell = row.getCell(colIdx); |
| | | if (cell == null) continue; |
| | | |
| | | String value = getCellStringValue(cell); |
| | | if (value.contains("签字") || value.contains("责任人") || |
| | | value.contains("执行") || value.contains("确认")) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 识别新表头开始 |
| | | */ |
| | | private boolean isNewHeaderStart(Row row) { |
| | | for (int colIdx = 0; colIdx < row.getLastCellNum(); colIdx++) { |
| | | Cell cell = row.getCell(colIdx); |
| | | if (cell == null) continue; |
| | | |
| | | String value = getCellStringValue(cell); |
| | | if ("序号".equals(value) || "点检项目".equals(value) || "周保养项目".equals(value)) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 检查行是否为空 |
| | | */ |
| | | private boolean isEmptyRow(Row row) { |
| | | if (row == null) return true; |
| | | for (int colIdx = 0; colIdx < row.getLastCellNum(); colIdx++) { |
| | | Cell cell = row.getCell(colIdx); |
| | | if (cell != null && cell.getCellType() != CellType.BLANK) { |
| | | String value = getCellStringValue(cell); |
| | | if (StringUtils.isNotBlank(value)) { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 使用正则提取字段 |
| | | */ |
| | | private String extractField(String text, String regex) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * 获取单元格字符串值 |
| | | * 提取每日点检项目 |
| | | */ |
| | | private List<EamMaintenanceStandardDetail> extractDailyItems(Sheet sheet, EamMaintenanceStandard standard, Map<Integer, String> rowErrors) { |
| | | // 使用多关键词匹配 |
| | | String[] primaryHeaders = {"点检项目", "日常点检", "每日检查"}; |
| | | String[] secondaryHeaders = {"完成数据/要求", "检查标准", "要求"}; |
| | | return extractItems(sheet, standard, primaryHeaders, secondaryHeaders, "DAY_INSPECTION", rowErrors); |
| | | } |
| | | |
| | | /** |
| | | * 提取周保养项目 |
| | | */ |
| | | private List<EamMaintenanceStandardDetail> extractWeeklyItems(Sheet sheet, EamMaintenanceStandard standard, Map<Integer, String> rowErrors) { |
| | | // 使用多关键词匹配 |
| | | String[] primaryHeaders = {"周保养项目", "周保养", "每周保养"}; |
| | | String[] secondaryHeaders = {"检查标准", "保养要求", "标准"}; |
| | | return extractItems(sheet, standard, primaryHeaders, secondaryHeaders, "WEEK_INSPECTION", rowErrors); |
| | | } |
| | | |
| | | /** |
| | | * 核心改进:优化表格区域识别和数据提取 |
| | | */ |
| | | private List<EamMaintenanceStandardDetail> extractItems(Sheet sheet, |
| | | EamMaintenanceStandard standard, |
| | | String[] primaryHeaders, |
| | | String[] secondaryHeaders, |
| | | String itemCategory, |
| | | Map<Integer, String> rowErrors) { |
| | | |
| | | // 1. 定位表格区域(精确匹配表头) |
| | | int startRow = findHeaderRow(sheet, primaryHeaders, secondaryHeaders); |
| | | if (startRow == -1) { |
| | | rowErrors.put(-1, "未找到" + Arrays.toString(primaryHeaders) + "表头区域"); |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | int endRow = findDataEnd(sheet, startRow + 1, "周保养项目"); |
| | | |
| | | // 提取日志(实际使用时可以去掉) |
| | | System.out.println("提取区域: " + (startRow + 1) + "行到" + (endRow + 1) + "行"); |
| | | |
| | | // 2. 提取数据行 |
| | | List<EamMaintenanceStandardDetail> details = new ArrayList<>(); |
| | | for (int rowIdx = startRow + 1; rowIdx <= endRow; rowIdx++) { |
| | | Row row = sheet.getRow(rowIdx); |
| | | if (row == null) continue; |
| | | |
| | | try { |
| | | // 序号列处理 |
| | | Cell seqCell = row.getCell(0); |
| | | if (seqCell == null || seqCell.getCellType() == CellType.BLANK) { |
| | | continue; |
| | | } |
| | | |
| | | // 获取序号值(支持数字和文本格式) |
| | | int seqValue = 0; |
| | | try { |
| | | if (seqCell.getCellType() == CellType.NUMERIC) { |
| | | seqValue = (int) seqCell.getNumericCellValue(); |
| | | } else if (seqCell.getCellType() == CellType.STRING) { |
| | | seqValue = Integer.parseInt(seqCell.getStringCellValue().trim()); |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | rowErrors.put(rowIdx + 1, "序号格式错误"); |
| | | continue; |
| | | } |
| | | |
| | | // 项目名称列(第二列) |
| | | Cell nameCell = row.getCell(1); |
| | | if (nameCell == null || nameCell.getCellType() == CellType.BLANK) { |
| | | continue; |
| | | } |
| | | String itemName = getCellStringValue(nameCell).trim(); |
| | | |
| | | // 要求/标准列(第三列) |
| | | String demand = ""; |
| | | if (row.getLastCellNum() >= 3) { |
| | | Cell demandCell = row.getCell(2); |
| | | if (demandCell != null) { |
| | | demand = getCellStringValue(demandCell).trim(); |
| | | } |
| | | } |
| | | |
| | | // 创建详情对象 |
| | | EamMaintenanceStandardDetail detail = new EamMaintenanceStandardDetail(); |
| | | detail.setStandardId(standard.getId()); |
| | | detail.setItemCode(seqValue); |
| | | detail.setItemName(itemName); |
| | | detail.setItemDemand(demand); |
| | | detail.setItemCategory(itemCategory); |
| | | details.add(detail); |
| | | |
| | | } catch (Exception e) { |
| | | rowErrors.put(rowIdx + 1, "解析错误: " + e.getMessage()); |
| | | } |
| | | } |
| | | return details; |
| | | } |
| | | |
| | | /** |
| | | * 获取行中所有单元格的字符串值 |
| | | */ |
| | | private List<String> getRowStringValues(Row row) { |
| | | List<String> values = new ArrayList<>(); |
| | | if (row == null) return values; |
| | | |
| | | for (int cellIdx = 0; cellIdx < row.getLastCellNum(); cellIdx++) { |
| | | Cell cell = row.getCell(cellIdx); |
| | | if (cell != null) { |
| | | values.add(getCellStringValue(cell)); |
| | | } else { |
| | | values.add(""); // 对于空单元格添加空字符串 |
| | | } |
| | | } |
| | | return values; |
| | | } |
| | | |
| | | /** |
| | | * 获取单元格字符串值(增强公式处理) |
| | | */ |
| | | private String getCellStringValue(Cell cell) { |
| | | if (cell == null) return ""; |
| | | if (cell == null) { |
| | | return ""; |
| | | } |
| | | // 保持不变,但添加数字类型处理 |
| | | if (cell.getCellType() == CellType.NUMERIC) { |
| | | // 整数处理 |
| | | double num = cell.getNumericCellValue(); |
| | | if (num == (int) num) { |
| | | return String.valueOf((int) num); |
| | | } |
| | | return String.valueOf(num); |
| | | } |
| | | switch (cell.getCellType()) { |
| | | case STRING: |
| | | return cell.getStringCellValue().trim(); |
| | |
| | | case BOOLEAN: |
| | | return String.valueOf(cell.getBooleanCellValue()); |
| | | case FORMULA: |
| | | return handleFormulaCell(cell); |
| | | return getFormulaCellValue(cell); |
| | | default: |
| | | return ""; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 处理公式单元格 |
| | | * 精确查找表头行 |
| | | */ |
| | | private String handleFormulaCell(Cell cell) { |
| | | private int findHeaderRow(Sheet sheet, String[] primaryHeaders, String[] secondaryHeaders) { |
| | | for (int rowIdx = 0; rowIdx <= sheet.getLastRowNum(); rowIdx++) { |
| | | Row row = sheet.getRow(rowIdx); |
| | | if (row == null) continue; |
| | | |
| | | String rowText = getRowStringValues(row).stream().collect(Collectors.joining()); |
| | | |
| | | // 检查主标题和副标题 |
| | | boolean hasPrimary = false; |
| | | boolean hasSecondary = false; |
| | | |
| | | for (String header : primaryHeaders) { |
| | | if (rowText.contains(header)) { |
| | | hasPrimary = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | for (String header : secondaryHeaders) { |
| | | if (rowText.contains(header)) { |
| | | hasSecondary = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (hasPrimary && hasSecondary) { |
| | | return rowIdx; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | /** |
| | | * 查找数据结束位置(根据您的Excel结构优化) |
| | | */ |
| | | private int findDataEnd(Sheet sheet, int startRow, String nextSectionKeyword) { |
| | | int consecutiveEmptyRows = 0; |
| | | final int MAX_EMPTY_ROWS = 3; |
| | | |
| | | for (int rowIdx = startRow; rowIdx <= sheet.getLastRowNum(); rowIdx++) { |
| | | Row row = sheet.getRow(rowIdx); |
| | | |
| | | // 关键改进1:空行处理 |
| | | if (isEssentiallyEmpty(row)) { |
| | | consecutiveEmptyRows++; |
| | | if (consecutiveEmptyRows >= MAX_EMPTY_ROWS) { |
| | | return rowIdx - consecutiveEmptyRows; |
| | | } |
| | | continue; |
| | | } else { |
| | | consecutiveEmptyRows = 0; |
| | | } |
| | | |
| | | // 关键改进2:结束标记检测 |
| | | String rowText = getRowStringValues(row).stream().collect(Collectors.joining()); |
| | | |
| | | // 根据您的Excel结构,签字行有特定格式 |
| | | if (rowText.contains("维护责任人签字")) { |
| | | return rowIdx - 1; |
| | | } |
| | | |
| | | // 检测下一个区域的开始(如周保养项目) |
| | | if (StringUtils.isNotBlank(nextSectionKeyword) && |
| | | rowText.contains(nextSectionKeyword)) { |
| | | return rowIdx - 1; |
| | | } |
| | | } |
| | | return sheet.getLastRowNum(); |
| | | } |
| | | |
| | | /** |
| | | * 判断条件:前两列为空即视为空行 |
| | | */ |
| | | private boolean isEssentiallyEmpty(Row row) { |
| | | if (row == null) return true; |
| | | |
| | | // 检查序号列 |
| | | Cell indexCell = row.getCell(0); |
| | | if (indexCell != null && indexCell.getCellType() != CellType.BLANK) { |
| | | return false; |
| | | } |
| | | |
| | | // 检查项目名称列 |
| | | Cell nameCell = row.getCell(1); |
| | | if (nameCell != null && nameCell.getCellType() != CellType.BLANK) { |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 获取公式单元格值 |
| | | */ |
| | | private String getFormulaCellValue(Cell cell) { |
| | | try { |
| | | FormulaEvaluator evaluator = cell.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator(); |
| | | Workbook workbook = cell.getSheet().getWorkbook(); |
| | | FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); |
| | | CellValue cellValue = evaluator.evaluate(cell); |
| | | |
| | | if (cellValue == null) return ""; |
| | | |
| | | if (cellValue == null) { |
| | | return ""; |
| | | } |
| | | switch (cellValue.getCellType()) { |
| | | case STRING: |
| | | return cellValue.getStringValue(); |
| | |
| | | return ""; |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("解析公式单元格失败"); |
| | | return ""; |
| | | } |
| | | } |
| | | |
| | | |
| | | private int findDataEnd(Sheet sheet, int startRow) { |
| | | int consecutiveEmptyRows = 0; |
| | | final int MAX_EMPTY_ROWS = 2; |
| | | boolean foundData = false; |
| | | |
| | | for (int rowIdx = startRow; rowIdx <= sheet.getLastRowNum(); rowIdx++) { |
| | | Row row = sheet.getRow(rowIdx); |
| | | |
| | | // 关键优化1:先检查是否为空行 |
| | | if (isEmptyRow(row)) { |
| | | consecutiveEmptyRows++; |
| | | if (consecutiveEmptyRows >= MAX_EMPTY_ROWS) { |
| | | return foundData ? rowIdx - consecutiveEmptyRows : startRow; |
| | | } |
| | | continue; |
| | | } else { |
| | | consecutiveEmptyRows = 0; |
| | | } |
| | | |
| | | // 关键优化2:严格限定结束标记的识别条件 |
| | | if (isStrongEndMarker(row)) { |
| | | return foundData ? rowIdx - 1 : startRow; |
| | | } |
| | | |
| | | // 关键优化3:标记已找到有效数据 |
| | | foundData = true; |
| | | } |
| | | return sheet.getLastRowNum(); |
| | | } |
| | | |
| | | // 增强版结束标记识别 |
| | | private boolean isStrongEndMarker(Row row) { |
| | | String rowText = String.join("", getRowStringValues(row)).toLowerCase(); |
| | | |
| | | return |
| | | // 精确匹配签字特征(出现在行首) |
| | | (rowText.startsWith("维护责任人签字") || |
| | | rowText.startsWith("执行人签字")) || |
| | | // 精确匹配新板块标题 |
| | | rowText.matches("^\\s*周保养项目\\s*$") || |
| | | rowText.contains("年度保养项目"); |
| | | } |
| | | |
| | | // 空行检测优化(允许部分列为空) |
| | | private boolean isEmptyRow(Row row) { |
| | | if (row == null) return true; |
| | | // 只检查前3列(序号列+项目名+要求) |
| | | for (int cellIdx = 0; cellIdx < Math.min(3, row.getLastCellNum()); cellIdx++) { |
| | | Cell cell = row.getCell(cellIdx); |
| | | if (cell != null && cell.getCellType() != CellType.BLANK) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | /*导入点检文件Excel--------------------------结束*/ |
| | | |
| | | /*导入二保三保文件Excel--------------------------开始*/ |