diff --git a/bonus-modules/bonus-material/src/main/java/com/bonus/material/codeCollection/mapper/WsMaInfoMapper.java b/bonus-modules/bonus-material/src/main/java/com/bonus/material/codeCollection/mapper/WsMaInfoMapper.java index 02f400bf..66617252 100644 --- a/bonus-modules/bonus-material/src/main/java/com/bonus/material/codeCollection/mapper/WsMaInfoMapper.java +++ b/bonus-modules/bonus-material/src/main/java/com/bonus/material/codeCollection/mapper/WsMaInfoMapper.java @@ -1,6 +1,7 @@ package com.bonus.material.codeCollection.mapper; import com.bonus.material.codeCollection.domain.WsMaInfo; +import com.bonus.material.ma.domain.Type; import org.apache.ibatis.annotations.MapKey; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -142,4 +143,18 @@ public interface WsMaInfoMapper { * @return 条数 */ int updateGadgetInfo(WsMaInfo info); + + /** + * 根据级别查询所有匹配的记录 + * @param level + * @param typeName + * @return + */ + // 根据级别查询所有r匹配的记录 + List listByLevelAndName(@Param("level") String level, @Param("typeName") String typeName); + + Type selectTypeRelation(@Param("parentLevel") String parentLevel, + @Param("parentName") String parentName, + @Param("childLevel") String childLevel, + @Param("childName") String childName); } diff --git a/bonus-modules/bonus-material/src/main/java/com/bonus/material/codeCollection/service/impl/WsMaInfoServiceImpl.java b/bonus-modules/bonus-material/src/main/java/com/bonus/material/codeCollection/service/impl/WsMaInfoServiceImpl.java index f2f3299a..34ae3627 100644 --- a/bonus-modules/bonus-material/src/main/java/com/bonus/material/codeCollection/service/impl/WsMaInfoServiceImpl.java +++ b/bonus-modules/bonus-material/src/main/java/com/bonus/material/codeCollection/service/impl/WsMaInfoServiceImpl.java @@ -8,15 +8,16 @@ import com.bonus.common.security.utils.SecurityUtils; import com.bonus.material.codeCollection.domain.WsMaInfo; import com.bonus.material.codeCollection.mapper.WsMaInfoMapper; import com.bonus.material.codeCollection.service.WsMaInfoService; +import com.bonus.material.ma.domain.Type; import com.bonus.material.ma.domain.vo.ExceptionEnum; +import com.bonus.material.ma.domain.vo.MaTypeVo; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ObjectUtils; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.hibernate.validator.internal.util.StringHelper; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -25,10 +26,9 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; /** * {@code WsMaInfoServiceImpl} @@ -329,112 +329,362 @@ public class WsMaInfoServiceImpl implements WsMaInfoService { } } - /** - * 导入数据 - * @param file - * @return - */ @Override public AjaxResult importTbData(MultipartFile file) { String fileName = file.getOriginalFilename(); if (fileName != null) { String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1); if (!GlobalConstants.XLSX.equalsIgnoreCase(fileExtension) && !GlobalConstants.XLS.equalsIgnoreCase(fileExtension)) { - // 文件后缀名不符合要求 return AjaxResult.error("导入失败:文件后缀名不符合要求,必须为xlsx或xls结尾"); } } + try { InputStream inputStream = file.getInputStream(); - Workbook workbook = new XSSFWorkbook(inputStream); + Workbook workbook = WorkbookFactory.create(inputStream); Sheet sheet = workbook.getSheetAt(0); - // 得到Excel的行数 + + // 得到Excel的行数(跳过表头行) int totalRows = sheet.getPhysicalNumberOfRows(); - // 检查是否有行数 if (totalRows <= 1) { throw new IllegalArgumentException("导入失败:Excel文件中没有数据,请检查后重新导入"); } - // 读取第一行表头 - Row headerRow = sheet.getRow(0); + + // 读取表头行(第一行) + Row headerRow = sheet.getRow(1); if (headerRow == null) { throw new IllegalArgumentException("导入失败:文件中没有表头"); } - // 获取表头的列数 - int totalCells = headerRow.getPhysicalNumberOfCells(); - // 预期的表头列数为5列,可以根据实际需求修改这个条件 - if (totalCells != 5) { - throw new IllegalArgumentException("导入失败:表头列数与预期不符,请检查导入模板"); - } - // 读取表头内容并验证每一列 - extracted(headerRow, totalCells); - //读取Excel表格数据,做非空及格式判断 - //extractedCell(sheet, totalRows, totalCells); - ExcelUtil util = new ExcelUtil<>(WsMaInfo.class); - List wsMaInfos = util.importExcel(file.getInputStream()); - int result = 0; - for (WsMaInfo wmInfo : wsMaInfos) { - /*List wsMaInfoList = mapper.queryByName(wmInfo); - if (CollectionUtils.isNotEmpty(wsMaInfoList)) { - for (WsMaInfo wmInfo : wsMaInfoList) { - if () { - //进行更新操作 - } else { - //新增操作 + // 验证表头 + validateHeader(headerRow); - } + List wsMaInfos = new ArrayList<>(); + int successCount = 0; + int failCount = 0; + List errorMessages = new ArrayList<>(); + + // 从第二行开始读取数据(索引1) + for (int rowNum = 2; rowNum < totalRows; rowNum++) { + Row row = sheet.getRow(rowNum); + if (row == null) { + continue; + } + + try { + WsMaInfo wsMaInfo = parseRowToWsMaInfo(row); + if (wsMaInfo != null) { + wsMaInfos.add(wsMaInfo); + // 新增操作 + wsMaInfo.setOptUser(SecurityUtils.getLoginUser().getSysUser().getNickName()); + mapper.addWsMaInfoData(wsMaInfo); + successCount++; } - }*/ + } catch (Exception e) { + failCount++; + errorMessages.add("第 " + (rowNum + 1) + " 行数据解析失败: " + e.getMessage()); + } } - if (result > 0) { - return AjaxResult.success(ExceptionEnum.SUCCESS.getMsg(), result); + + // 处理结果返回 + if (failCount == 0) { + return AjaxResult.success("导入成功,共导入 " + successCount + " 条数据"); + } else { + String errorMsg = "导入完成,成功 " + successCount + " 条,失败 " + failCount + " 条。"; + if (!errorMessages.isEmpty()) { + errorMsg += "错误信息:" + String.join("; ", errorMessages); + } + return AjaxResult.error(errorMsg); } + } catch (IOException e) { - e.printStackTrace(); + log.error("导入文件读取失败", e); + return AjaxResult.error("导入失败:文件读取异常"); + } catch (IllegalArgumentException e) { + return AjaxResult.error(e.getMessage()); + } catch (Exception e) { + log.error("导入过程发生异常", e); + return AjaxResult.error("导入失败:系统异常"); } - return AjaxResult.error(ExceptionEnum.SAVE_TO_DATABASE.getCode(), ExceptionEnum.SAVE_TO_DATABASE.getMsg()); } /** - * 读取Excel表头模板方法抽取 - * @param headerRow - * @param totalCells + * 验证表头格式 */ - private void extracted(Row headerRow, int totalCells) { - for (int cellNum = 0; cellNum < totalCells; cellNum++) { - Cell cell = headerRow.getCell(cellNum); - // 获取单元格内容并去除首尾空格 - String headerValue = cell.getStringCellValue().trim(); - // 根据列索引进行验证 - switch (cellNum) { - case 0: - if (!"姓名".equals(headerValue)) { - throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); - } - break; - case 1: - if (!"性别(0 女 1 男)".equals(headerValue)) { - throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); - } - break; - case 2: - if (!"岗位工种".equals(headerValue)) { - throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); - } - break; - case 3: - if (!"身份证号码".equals(headerValue)) { - throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); - } - break; - case 4: - if (!"电话".equals(headerValue)) { - throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); - } - break; - default: - break; + private void validateHeader(Row headerRow) { + String[] expectedHeaders = { + "序号", "机具名称", "规格型号", "机具编号", "本次检验时间", + "下次检验时间", "检修员", "检验员", "联系方式", "结果" + }; + + int cellCount = headerRow.getPhysicalNumberOfCells(); + if (cellCount < expectedHeaders.length) { + throw new IllegalArgumentException("导入失败:表头列数不足,请检查导入模板"); + } + + for (int i = 0; i < expectedHeaders.length; i++) { + Cell cell = headerRow.getCell(i); + if (cell == null) { + throw new IllegalArgumentException("导入失败:第 " + (i + 1) + " 列表头为空"); + } + + String headerValue = getCellValueAsString(cell).trim(); + if (!expectedHeaders[i].equals(headerValue)) { + throw new IllegalArgumentException("导入失败:第 " + (i + 1) + " 列表头 '" + headerValue + + "' 与预期 '" + expectedHeaders[i] + "' 不符"); } } } + + /** + * 解析单行数据到WsMaInfo对象 + */ + private WsMaInfo parseRowToWsMaInfo(Row row) { + WsMaInfo wsMaInfo = new WsMaInfo(); + + // 机具名称 + String maName = getCellValueAsString(row.getCell(1)); + if (StringHelper.isNullOrEmptyString(maName)){ + throw new IllegalArgumentException("机具名称不能为空"); + } + wsMaInfo.setMaName(maName); + + // 规格型号 + String maModel = getCellValueAsString(row.getCell(2)); + if (StringHelper.isNullOrEmptyString(maModel)){ + throw new IllegalArgumentException("规格型号不能为空"); + } + wsMaInfo.setMaModel(maModel); + + // 机具编号 + String maCode = getCellValueAsString(row.getCell(3)); + if (StringUtils.isEmpty(maCode)) { + throw new IllegalArgumentException("机具编号不能为空"); + } + wsMaInfo.setMaCode(maCode); + + // 本次检验时间 + String thisCheckTime = getCellValueAsString(row.getCell(4)); + if (!isValidDate(thisCheckTime)) { + throw new IllegalArgumentException("本次检验时间格式不正确"); + } + wsMaInfo.setThisCheckTime(thisCheckTime); + + // 下次检验时间 + String nextCheckTime = getCellValueAsString(row.getCell(5)); + if (!isValidDate(nextCheckTime)) { + throw new IllegalArgumentException("下次检验时间格式不正确"); + } + wsMaInfo.setNextCheckTime(nextCheckTime); + + // 检修员 + wsMaInfo.setRepairMan(getCellValueAsString(row.getCell(6))); + + // 检验员 + wsMaInfo.setCheckMan(getCellValueAsString(row.getCell(7))); + + // 联系方式 + wsMaInfo.setPhone(getCellValueAsString(row.getCell(8))); + + // 结果 + String result = getCellValueAsString(row.getCell(9)); + if (!"合格".equals(result) && !"不合格".equals(result)) { + throw new IllegalArgumentException("检验结果必须是'合格'或'不合格'"); + } + wsMaInfo.setResult(result); + + // 验证设备类型和规格型号的层级关系 + validateTypeHierarchy(wsMaInfo, maName, maModel); + + //判断该类型下编码是否已存在 + WsMaInfo info = mapper.getInfoByTypeAndModelAndCode(wsMaInfo); + if (info != null){ + throw new IllegalArgumentException("该类型下编码已存在"); + } + + return wsMaInfo; + } + + /** + * 验证设备类型和规格型号的层级关系 + */ + /** + * 通过关联查询验证层级关系(更高效) + */ + private void validateTypeHierarchy(WsMaInfo wsMaInfo, String typeName, String modelName) { + // 使用关联查询直接验证层级关系 + Type relation = mapper.selectTypeRelation("3", typeName, "4", modelName); + + if (relation == null) { + throw new IllegalArgumentException("规格型号 '" + modelName + "' 不属于设备类型 '" + typeName + "' 或不存在"); + } + + wsMaInfo.setModelId(String.valueOf(relation.getTypeId())); + } + + /** + * 更新已存在的记录 + */ + private void updateExistingRecord(WsMaInfo existing, WsMaInfo newData) { + existing.setThisCheckTime(newData.getThisCheckTime()); + existing.setNextCheckTime(newData.getNextCheckTime()); + existing.setRepairMan(newData.getRepairMan()); + existing.setCheckMan(newData.getCheckMan()); + existing.setPhone(newData.getPhone()); + existing.setResult(newData.getResult()); + existing.setOptTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + existing.setOptUser(SecurityUtils.getUsername()); + } + + /** + * 获取单元格值的通用方法 + */ + private String getCellValueAsString(Cell cell) { + if (cell == null) { + return ""; + } + + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue().trim(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + return new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue()); + } else { + return String.valueOf((int) cell.getNumericCellValue()); + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + return cell.getCellFormula(); + default: + return ""; + } + } + + /** + * 验证日期格式 + */ + private boolean isValidDate(String dateStr) { + if (StringUtils.isEmpty(dateStr)) { + return false; + } + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + sdf.setLenient(false); + sdf.parse(dateStr); + return true; + } catch (ParseException e) { + return false; + } + } + +// /** +// * 导入数据 +// * @param file +// * @return +// */ +// @Override +// public AjaxResult importTbData(MultipartFile file) { +// String fileName = file.getOriginalFilename(); +// if (fileName != null) { +// String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1); +// if (!GlobalConstants.XLSX.equalsIgnoreCase(fileExtension) && !GlobalConstants.XLS.equalsIgnoreCase(fileExtension)) { +// // 文件后缀名不符合要求 +// return AjaxResult.error("导入失败:文件后缀名不符合要求,必须为xlsx或xls结尾"); +// } +// } +// try { +// InputStream inputStream = file.getInputStream(); +// Workbook workbook = new XSSFWorkbook(inputStream); +// Sheet sheet = workbook.getSheetAt(0); +// // 得到Excel的行数 +// int totalRows = sheet.getPhysicalNumberOfRows(); +// // 检查是否有行数 +// if (totalRows <= 1) { +// throw new IllegalArgumentException("导入失败:Excel文件中没有数据,请检查后重新导入"); +// } +// // 读取第一行表头 +// Row headerRow = sheet.getRow(0); +// if (headerRow == null) { +// throw new IllegalArgumentException("导入失败:文件中没有表头"); +// } +// // 获取表头的列数 +// int totalCells = headerRow.getPhysicalNumberOfCells(); +// // 预期的表头列数为5列,可以根据实际需求修改这个条件 +// if (totalCells != 5) { +// throw new IllegalArgumentException("导入失败:表头列数与预期不符,请检查导入模板"); +// } +// // 读取表头内容并验证每一列 +// extracted(headerRow, totalCells); +// //读取Excel表格数据,做非空及格式判断 +// //extractedCell(sheet, totalRows, totalCells); +// ExcelUtil util = new ExcelUtil<>(WsMaInfo.class); +// List wsMaInfos = util.importExcel(file.getInputStream()); +// int result = 0; +// for (WsMaInfo wmInfo : wsMaInfos) { +// /*List wsMaInfoList = mapper.queryByName(wmInfo); +// if (CollectionUtils.isNotEmpty(wsMaInfoList)) { +// for (WsMaInfo wmInfo : wsMaInfoList) { +// if () { +// //进行更新操作 +// +// } else { +// //新增操作 +// +// } +// } +// }*/ +// } +// if (result > 0) { +// return AjaxResult.success(ExceptionEnum.SUCCESS.getMsg(), result); +// } +// } catch (IOException e) { +// e.printStackTrace(); +// } +// return AjaxResult.error(ExceptionEnum.SAVE_TO_DATABASE.getCode(), ExceptionEnum.SAVE_TO_DATABASE.getMsg()); +// } +// +// /** +// * 读取Excel表头模板方法抽取 +// * @param headerRow +// * @param totalCells +// */ +// private void extracted(Row headerRow, int totalCells) { +// for (int cellNum = 0; cellNum < totalCells; cellNum++) { +// Cell cell = headerRow.getCell(cellNum); +// // 获取单元格内容并去除首尾空格 +// String headerValue = cell.getStringCellValue().trim(); +// // 根据列索引进行验证 +// switch (cellNum) { +// case 0: +// if (!"姓名".equals(headerValue)) { +// throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); +// } +// break; +// case 1: +// if (!"性别(0 女 1 男)".equals(headerValue)) { +// throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); +// } +// break; +// case 2: +// if (!"岗位工种".equals(headerValue)) { +// throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); +// } +// break; +// case 3: +// if (!"身份证号码".equals(headerValue)) { +// throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); +// } +// break; +// case 4: +// if (!"电话".equals(headerValue)) { +// throw new IllegalArgumentException("第 " + (cellNum + 1) + " 列表头列名与预期不符,请检查导入模板"); +// } +// break; +// default: +// break; +// } +// } +// } } diff --git a/bonus-modules/bonus-material/src/main/resources/mapper/material/codeCollection/WsMaInfoMapper.xml b/bonus-modules/bonus-material/src/main/resources/mapper/material/codeCollection/WsMaInfoMapper.xml index a2867f62..327193c6 100644 --- a/bonus-modules/bonus-material/src/main/resources/mapper/material/codeCollection/WsMaInfoMapper.xml +++ b/bonus-modules/bonus-material/src/main/resources/mapper/material/codeCollection/WsMaInfoMapper.xml @@ -122,7 +122,8 @@ + + INSERT INTO ws_ma_info (ma_name, ma_model, ma_code, supplier, this_check_time, next_check_time,