From 880415b514f2d51bee3944e1f79a100a7ff24866 Mon Sep 17 00:00:00 2001 From: qiankanghui Date: Thu, 9 Jul 2026 13:11:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(eam):=20=E6=96=B0=E5=A2=9E=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97=E7=9A=84Excel?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入Apache POI依赖用于Excel文件处理 - 实现点检项目导入模板下载功能 - 实现维保项目导入模板下载功能 - 实现点检项目批量导入Excel功能 - 实现维保项目批量导入Excel功能 - 添加Excel文件解析和数据验证逻辑 - 实现部门名称到编码的自动转换功能 - 完善导入过程中的错误处理和提示信息 --- .../modules/pms/controller/EamController.java | 238 ++++++++++- .../sys/modules/pms/service/EamService.java | 25 ++ .../pms/service/Impl/EamServiceImpl.java | 385 ++++++++++++++++++ 3 files changed, 646 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/xujie/sys/modules/pms/controller/EamController.java b/src/main/java/com/xujie/sys/modules/pms/controller/EamController.java index 180b9956..6575fbcb 100644 --- a/src/main/java/com/xujie/sys/modules/pms/controller/EamController.java +++ b/src/main/java/com/xujie/sys/modules/pms/controller/EamController.java @@ -25,13 +25,23 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import jakarta.servlet.http.HttpServletResponse; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.*; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; + import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,7 +68,7 @@ public class EamController { /** * @Description 维修执行工单导出 - * @Title + * @Title * @author qkh * @date 2026/2/5 **/ @@ -1560,7 +1570,7 @@ public class EamController { * @Description TODO * @Title eamDocumentTypeEdit * @param data - * @author jiayang_yue + * @author jiayang_yue * @data 2024/6/11 13:24 * @return java.lang.Object **/ @@ -2602,4 +2612,228 @@ public class EamController { return R.ok().put("itemData",itemData); } + /** + * @Description 下载点检项目导入模板 + * @Title downloadEamPropertiesItemTemplate + * @date 2026/7/9 + */ + @GetMapping("/downloadEamPropertiesItemTemplate") + public ResponseEntity downloadEamPropertiesItemTemplate() { + try { + // 直接在内存中生成 Excel 模板 + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFSheet sheet = workbook.createSheet("点检项目"); + + // 创建表头样式 + XSSFCellStyle headerStyle = workbook.createCellStyle(); + XSSFFont headerFont = workbook.createFont(); + headerFont.setBold(true); + headerStyle.setFont(headerFont); + headerStyle.setAlignment(HorizontalAlignment.CENTER); + headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); + headerStyle.setBorderTop(BorderStyle.THIN); + headerStyle.setBorderBottom(BorderStyle.THIN); + headerStyle.setBorderLeft(BorderStyle.THIN); + headerStyle.setBorderRight(BorderStyle.THIN); + headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + // 创建表头行 + XSSFRow headerRow = sheet.createRow(0); + String[] headers = { + "部门", "点检项目编码", "点检项目名称", "检测值类型", + "参照值", "最大值", "最小值", "是否值可选", "图片是否必填", + "生产管控", "点检方法说明" + }; + for (int i = 0; i < headers.length; i++) { + XSSFCell cell = headerRow.createCell(i); + cell.setCellValue(headers[i]); + cell.setCellStyle(headerStyle); + } + + // 添加示例数据行 + XSSFRow dataRow1 = sheet.createRow(1); + dataRow1.createCell(0).setCellValue("R022"); + dataRow1.createCell(1).setCellValue("A00001"); + dataRow1.createCell(2).setCellValue("设备外观检查"); + dataRow1.createCell(3).setCellValue("T"); + dataRow1.createCell(4).setCellValue("正常"); + dataRow1.createCell(5).setCellValue(""); + dataRow1.createCell(6).setCellValue(""); + dataRow1.createCell(7).setCellValue("N"); + dataRow1.createCell(8).setCellValue("N"); + dataRow1.createCell(9).setCellValue("N"); + dataRow1.createCell(10).setCellValue("目视检查设备外观是否有损坏"); + + // 设置列宽 + sheet.setColumnWidth(0, 12 * 256); // 部门 + sheet.setColumnWidth(1, 18 * 256); // 点检项目编码 + sheet.setColumnWidth(2, 25 * 256); // 点检项目名称 + sheet.setColumnWidth(3, 12 * 256); // 检测值类型 + sheet.setColumnWidth(4, 12 * 256); // 参照值 + sheet.setColumnWidth(5, 12 * 256); // 最大值 + sheet.setColumnWidth(6, 12 * 256); // 最小值 + sheet.setColumnWidth(7, 12 * 256); // 是否值可选 + sheet.setColumnWidth(8, 12 * 256); // 图片是否必填 + sheet.setColumnWidth(9, 12 * 256); // 生产管控 + sheet.setColumnWidth(10, 30 * 256); // 点检方法说明 + + // 写入到字节数组 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + workbook.write(outputStream); + workbook.close(); + + byte[] bytes = outputStream.toByteArray(); + ByteArrayResource resource = new ByteArrayResource(bytes); + + String fileName = "点检项目导入模板.xlsx"; + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()) + .replaceAll("\\+", "%20"); + + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename*=UTF-8''" + encodedFileName) + .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(bytes.length)) + .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) + .body(resource); + + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.internalServerError().build(); + } + } + + /** + * @Description 批量导入点检项目 + * @Title uploadEamPropertiesItemExcel + * @date 2026/7/9 + */ + @PostMapping("/uploadEamPropertiesItemExcel") + public R uploadEamPropertiesItemExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "createBy", required = false) String createBy, + @RequestParam(value = "site", required = false) String site, + @RequestParam(value = "buNo", required = false) String buNo) { + try { + eamService.uploadEamPropertiesItemExcel(file, createBy, site, buNo); + return R.ok().put("msg", "导入成功"); + } catch (Exception e) { + e.printStackTrace(); + return R.error(e.getMessage()); + } + } + + /** + * @Description 下载维保项目导入模板 + * @Title downloadEamMaintenanceItemTemplate + * @date 2026/7/9 + */ + @GetMapping("/downloadEamMaintenanceItemTemplate") + public ResponseEntity downloadEamMaintenanceItemTemplate() { + try { + // 直接在内存中生成 Excel 模板 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + try (XSSFWorkbook workbook = new XSSFWorkbook()) { + XSSFSheet sheet = workbook.createSheet("维保项目"); + + // 创建表头样式 + XSSFCellStyle headerStyle = workbook.createCellStyle(); + XSSFFont headerFont = workbook.createFont(); + headerFont.setBold(true); + headerStyle.setFont(headerFont); + headerStyle.setAlignment(HorizontalAlignment.CENTER); + headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); + headerStyle.setBorderTop(BorderStyle.THIN); + headerStyle.setBorderBottom(BorderStyle.THIN); + headerStyle.setBorderLeft(BorderStyle.THIN); + headerStyle.setBorderRight(BorderStyle.THIN); + headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + // 创建表头行 + XSSFRow headerRow = sheet.createRow(0); + String[] headers = { + "维保项目编码", "部门", "维保项目名称", "维保方法说明", + "检测值类型", "参照值", "最大值", "最小值", + "是否值可选", "是否图片必填" + }; + for (int i = 0; i < headers.length; i++) { + XSSFCell cell = headerRow.createCell(i); + cell.setCellValue(headers[i]); + cell.setCellStyle(headerStyle); + } + + // 添加示例数据行 + XSSFRow dataRow1 = sheet.createRow(1); + dataRow1.createCell(0).setCellValue("B00001"); + dataRow1.createCell(1).setCellValue("R022"); + dataRow1.createCell(2).setCellValue("设备日常保养"); + dataRow1.createCell(3).setCellValue("每日对设备进行日常保养检查"); + dataRow1.createCell(4).setCellValue("T"); + dataRow1.createCell(5).setCellValue("正常"); + dataRow1.createCell(6).setCellValue(""); + dataRow1.createCell(7).setCellValue(""); + dataRow1.createCell(8).setCellValue("N"); + dataRow1.createCell(9).setCellValue("N"); + + // 设置列宽 + sheet.setColumnWidth(0, 18 * 256); // 维保项目编码 + sheet.setColumnWidth(1, 12 * 256); // 部门 + sheet.setColumnWidth(2, 25 * 256); // 维保项目名称 + sheet.setColumnWidth(3, 30 * 256); // 维保方法说明 + sheet.setColumnWidth(4, 12 * 256); // 检测值类型 + sheet.setColumnWidth(5, 12 * 256); // 参照值 + sheet.setColumnWidth(6, 12 * 256); // 最大值 + sheet.setColumnWidth(7, 12 * 256); // 最小值 + sheet.setColumnWidth(8, 12 * 256); // 是否值可选 + sheet.setColumnWidth(9, 12 * 256); // 是否图片必填 + + // 写入到字节数组 + workbook.write(outputStream); + workbook.close(); + } + + // 刷新并关闭输出流 + outputStream.flush(); + outputStream.close(); + + byte[] bytes = outputStream.toByteArray(); + ByteArrayResource resource = new ByteArrayResource(bytes); + + String fileName = "维保项目导入模板.xlsx"; + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()) + .replaceAll("\\+", "%20"); + + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename*=UTF-8''" + encodedFileName) + .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(bytes.length)) + .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) + .body(resource); + + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.internalServerError().build(); + } + } + + /** + * @Description 批量导入维保项目 + * @Title uploadEamMaintenanceItemExcel + * @date 2026/7/9 + */ + @PostMapping("/uploadEamMaintenanceItemExcel") + public R uploadEamMaintenanceItemExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "createBy", required = false) String createBy, + @RequestParam(value = "site", required = false) String site, + @RequestParam(value = "buNo", required = false) String buNo) { + try { + eamService.uploadEamMaintenanceItemExcel(file, createBy, site, buNo); + return R.ok().put("msg", "导入成功"); + } catch (Exception e) { + e.printStackTrace(); + return R.error(e.getMessage()); + } + } + } diff --git a/src/main/java/com/xujie/sys/modules/pms/service/EamService.java b/src/main/java/com/xujie/sys/modules/pms/service/EamService.java index 839b44d0..9a184569 100644 --- a/src/main/java/com/xujie/sys/modules/pms/service/EamService.java +++ b/src/main/java/com/xujie/sys/modules/pms/service/EamService.java @@ -17,6 +17,7 @@ import com.xujie.sys.modules.sys.entity.SysUserEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.multipart.MultipartFile; import java.util.List; public interface EamService { @@ -1231,4 +1232,28 @@ public interface EamService { List eamWorkOrderSearchForDefectExport(EamWorkOrderInData data); List eamDefectRecordExport(EamWorkOrderInData data); + + /** + * @Description 批量导入点检项目Excel + * @Title uploadEamPropertiesItemExcel + * @param file + * @param createBy + * @param site + * @param buNo + * @date 2026/7/9 + * @return void + */ + void uploadEamPropertiesItemExcel(MultipartFile file, String createBy, String site, String buNo); + + /** + * @Description 批量导入维保项目Excel + * @Title uploadEamMaintenanceItemExcel + * @param file + * @param createBy + * @param site + * @param buNo + * @date 2026/7/9 + * @return void + */ + void uploadEamMaintenanceItemExcel(MultipartFile file, String createBy, String site, String buNo); } diff --git a/src/main/java/com/xujie/sys/modules/pms/service/Impl/EamServiceImpl.java b/src/main/java/com/xujie/sys/modules/pms/service/Impl/EamServiceImpl.java index 8c96f63b..25a2842e 100644 --- a/src/main/java/com/xujie/sys/modules/pms/service/Impl/EamServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/pms/service/Impl/EamServiceImpl.java @@ -49,9 +49,12 @@ import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; +import org.apache.poi.xssf.usermodel.*; +import org.springframework.web.multipart.MultipartFile; import jakarta.mail.internet.MimeMessage; import java.io.IOException; +import java.io.InputStream; import java.math.BigDecimal; import java.time.Duration; import java.util.*; @@ -60,6 +63,8 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import static org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted; + @Service @Slf4j public class EamServiceImpl implements EamService { @@ -4344,4 +4349,384 @@ public class EamServiceImpl implements EamService { QcItemData result = eamMapper.getEamPropertiesItemByItemNo(data); return result; } + + @Override + public void uploadEamPropertiesItemExcel(MultipartFile file, String createBy, String site, String buNo) { + try { + // 验证必填参数 + if (StringUtils.isEmpty(site)) { + throw new RuntimeException("site不能为空"); + } + if (StringUtils.isEmpty(buNo)) { + throw new RuntimeException("buNo不能为空"); + } + + InputStream is = file.getInputStream(); + XSSFWorkbook workbook = new XSSFWorkbook(is); + XSSFSheet sheet = workbook.getSheetAt(0); + int rows = sheet.getPhysicalNumberOfRows(); + + if (rows < 2) { + throw new RuntimeException("Excel文件中没有数据"); + } + int successCount = 0; + int errorCount = 0; + StringBuilder errorMsg = new StringBuilder(); + for (int i = 1; i < rows; i++) { + XSSFRow row = sheet.getRow(i); + if (row == null) { + continue; + } + try { + EamPropertiesItemData itemData = new EamPropertiesItemData(); + + // 直接使用前端传入的site和buNo + itemData.setSite(site); + itemData.setBuNo(buNo); + + // 部门(第0列,原第1列) + String checkType = getCellValue(row.getCell(0)); + if (StringUtils.isEmpty(checkType)) { + throw new RuntimeException("部门不能为空"); + } + + // 转换部门名称为编码 + checkType = convertCheckType(checkType); + itemData.setCheckType(checkType); + + // 点检项目编码(第1列,原第2列) + String itemNo = getCellValue(row.getCell(1)); + if (StringUtils.isEmpty(itemNo)) { + throw new RuntimeException("点检项目编码不能为空"); + } + itemData.setItemNo(itemNo.toUpperCase()); + + // 点检项目名称(第2列,原第3列) + String itemDesc = getCellValue(row.getCell(2)); + if (StringUtils.isEmpty(itemDesc)) { + throw new RuntimeException("点检项目名称不能为空"); + } + itemData.setItemDesc(itemDesc); + + // 检测值类型(第3列,原第4列) + String valueType = getCellValue(row.getCell(3)); + if (StringUtils.isEmpty(valueType)) { + throw new RuntimeException("检测值类型不能为空"); + } + if (!"T".equals(valueType) && !"N".equals(valueType)) { + throw new RuntimeException("检测值类型只能是T(文本)或N(数字)"); + } + itemData.setValueType(valueType); + itemData.setValueTypeDb(valueType); + + // 参照值(第4列,原第5列) + String defaultValue = getCellValue(row.getCell(4)); + itemData.setDefaultValue(defaultValue); + + // 最大值(第5列,原第6列) + String maxValueStr = getCellValue(row.getCell(5)); + if (!StringUtils.isEmpty(maxValueStr)) { + try { + itemData.setMaxValue(Double.parseDouble(maxValueStr)); + } catch (NumberFormatException e) { + throw new RuntimeException("最大值格式错误"); + } + } + + // 最小值(第6列,原第7列) + String minValueStr = getCellValue(row.getCell(6)); + if (!StringUtils.isEmpty(minValueStr)) { + try { + itemData.setMinValue(Double.parseDouble(minValueStr)); + } catch (NumberFormatException e) { + throw new RuntimeException("最小值格式错误"); + } + } + + // 是否值可选(第7列,原第8列) + String valueChooseFlag = getCellValue(row.getCell(7)); + if (StringUtils.isEmpty(valueChooseFlag)) { + valueChooseFlag = "N"; + } + if (!"Y".equals(valueChooseFlag) && !"N".equals(valueChooseFlag)) { + throw new RuntimeException("是否值可选只能是Y或N"); + } + itemData.setValueChooseFlag(valueChooseFlag); + + // 图片是否必填(第8列,原第9列) + String imageFlag = getCellValue(row.getCell(8)); + if (StringUtils.isEmpty(imageFlag)) { + imageFlag = "N"; + } + if (!"Y".equals(imageFlag) && !"N".equals(imageFlag)) { + throw new RuntimeException("图片是否必填只能是Y或N"); + } + itemData.setImageFlag(imageFlag); + + // 生产管控(第9列,原第10列) + String produceControlFlag = getCellValue(row.getCell(9)); + if (StringUtils.isEmpty(produceControlFlag)) { + produceControlFlag = "N"; + } + if (!"Y".equals(produceControlFlag) && !"N".equals(produceControlFlag)) { + throw new RuntimeException("生产管控只能是Y或N"); + } + itemData.setProduceControlFlag(produceControlFlag); + + // 点检方法说明(第10列,原第11列) + String itemRemark = getCellValue(row.getCell(10)); + itemData.setItemRemark(itemRemark); + + // 设置其他字段 + itemData.setItemType("A"); + itemData.setCreatedBy(createBy); + itemData.setUpdateBy(createBy); + + // 检查是否已存在 + List checkList = eamDao.checkEamPropertiesItem(itemData); + if (!checkList.isEmpty()) { + throw new RuntimeException("点检项目编码已存在"); + } + + // 保存数据 + log.info("准备保存点检项目 - site: {}, buNo: {}, itemNo: {}, itemDesc: {}", + itemData.getSite(), itemData.getBuNo(), itemData.getItemNo(), itemData.getItemDesc()); + eamDao.saveNewEamPropertiesItem(itemData); + successCount++; + log.info("成功保存点检项目: {}", itemData.getItemNo()); + + } catch (Exception e) { + errorCount++; + errorMsg.append("第").append(i + 1).append("行: ").append(e.getMessage()).append("; "); + log.error("导入点检项目第{}行失败: {}", i + 1, e.getMessage()); + } + } + workbook.close(); + if (errorCount > 0) { + throw new RuntimeException("导入完成,成功" + successCount + "条,失败" + errorCount + "条。错误信息:" + errorMsg.toString()); + } + log.info("点检项目导入完成,成功{}条", successCount); + } catch (IOException e) { + log.error("读取Excel文件失败", e); + throw new RuntimeException("读取Excel文件失败: " + e.getMessage()); + } catch (Exception e) { + log.error("导入点检项目失败", e); + throw new RuntimeException(e.getMessage()); + } + } + /** + * 转换部门名称为编码 + * @param checkType 部门名称或编码 + * @return 部门编码(R022/R023/R024) + */ + private String convertCheckType(String checkType) { + if (StringUtils.isEmpty(checkType)) { + return checkType; + } + + // 如果是中文名称,转换为编码 + if ("生产".equals(checkType)) { + return "R022"; + } else if ("设备".equals(checkType)) { + return "R023"; + } else if ("质量".equals(checkType)) { + return "R024"; + } + + // 如果已经是编码,验证是否有效 + if ("R022".equals(checkType) || "R023".equals(checkType) || "R024".equals(checkType)) { + return checkType; + } + + // 既不是中文名称也不是有效编码,抛出异常 + throw new RuntimeException("部门值无效:" + checkType + ",只能是'生产'、'设备'、'质量'或'R022'、'R023'、'R024'"); + } + + @Override + public void uploadEamMaintenanceItemExcel(MultipartFile file, String createBy, String site, String buNo) { + try { + // 验证必填参数 + if (StringUtils.isEmpty(site)) { + throw new RuntimeException("site不能为空"); + } + if (StringUtils.isEmpty(buNo)) { + throw new RuntimeException("buNo不能为空"); + } + + InputStream is = file.getInputStream(); + XSSFWorkbook workbook = new XSSFWorkbook(is); + XSSFSheet sheet = workbook.getSheetAt(0); + int rows = sheet.getPhysicalNumberOfRows(); + + if (rows < 2) { + throw new RuntimeException("Excel文件中没有数据"); + } + int successCount = 0; + int errorCount = 0; + StringBuilder errorMsg = new StringBuilder(); + for (int i = 1; i < rows; i++) { + XSSFRow row = sheet.getRow(i); + if (row == null) { + continue; + } + try { + EamPropertiesItemData itemData = new EamPropertiesItemData(); + + // 直接使用前端传入的site和buNo + itemData.setSite(site); + itemData.setBuNo(buNo); + + // 维保项目编码(第0列) + String itemNo = getCellValue(row.getCell(0)); + if (StringUtils.isEmpty(itemNo)) { + throw new RuntimeException("维保项目编码不能为空"); + } + itemData.setItemNo(itemNo.toUpperCase()); + + // 部门(第1列) + String checkType = getCellValue(row.getCell(1)); + if (StringUtils.isEmpty(checkType)) { + throw new RuntimeException("部门不能为空"); + } + // 转换部门名称为编码 + checkType = convertCheckType(checkType); + itemData.setCheckType(checkType); + + // 维保项目名称(第2列) + String itemDesc = getCellValue(row.getCell(2)); + if (StringUtils.isEmpty(itemDesc)) { + throw new RuntimeException("维保项目名称不能为空"); + } + itemData.setItemDesc(itemDesc); + + // 维保方法说明(第3列) + String itemRemark = getCellValue(row.getCell(3)); + itemData.setItemRemark(itemRemark); + + // 检测值类型(第4列) + String valueType = getCellValue(row.getCell(4)); + if (StringUtils.isEmpty(valueType)) { + throw new RuntimeException("检测值类型不能为空"); + } + if (!"T".equals(valueType) && !"N".equals(valueType)) { + throw new RuntimeException("检测值类型只能是T(文本)或N(数字)"); + } + itemData.setValueType(valueType); + itemData.setValueTypeDb(valueType); + + // 参照值(第5列) + String defaultValue = getCellValue(row.getCell(5)); + itemData.setDefaultValue(defaultValue); + + // 最大值(第6列) + String maxValueStr = getCellValue(row.getCell(6)); + if (!StringUtils.isEmpty(maxValueStr)) { + try { + itemData.setMaxValue(Double.parseDouble(maxValueStr)); + } catch (NumberFormatException e) { + throw new RuntimeException("最大值格式错误"); + } + } + + // 最小值(第7列) + String minValueStr = getCellValue(row.getCell(7)); + if (!StringUtils.isEmpty(minValueStr)) { + try { + itemData.setMinValue(Double.parseDouble(minValueStr)); + } catch (NumberFormatException e) { + throw new RuntimeException("最小值格式错误"); + } + } + + // 是否值可选(第8列) + String valueChooseFlag = getCellValue(row.getCell(8)); + if (StringUtils.isEmpty(valueChooseFlag)) { + valueChooseFlag = "N"; + } + if (!"Y".equals(valueChooseFlag) && !"N".equals(valueChooseFlag)) { + throw new RuntimeException("是否值可选只能是Y或N"); + } + itemData.setValueChooseFlag(valueChooseFlag); + + // 图片必填(第9列) + String imageFlag = getCellValue(row.getCell(9)); + if (StringUtils.isEmpty(imageFlag)) { + imageFlag = "N"; + } + if (!"Y".equals(imageFlag) && !"N".equals(imageFlag)) { + throw new RuntimeException("图片必填只能是Y或N"); + } + itemData.setImageFlag(imageFlag); + + // 设置其他字段 - 注意:维保项目的itemType为B + itemData.setItemType("B"); + itemData.setCreatedBy(createBy); + itemData.setUpdateBy(createBy); + + // 检查是否已存在 + List checkList = eamDao.checkEamPropertiesItem(itemData); + if (!checkList.isEmpty()) { + throw new RuntimeException("维保项目编码已存在"); + } + + // 保存数据 + log.info("准备保存维保项目 - site: {}, buNo: {}, itemNo: {}, itemDesc: {}", + itemData.getSite(), itemData.getBuNo(), itemData.getItemNo(), itemData.getItemDesc()); + eamDao.saveNewEamPropertiesItem(itemData); + successCount++; + log.info("成功保存维保项目: {}", itemData.getItemNo()); + + } catch (Exception e) { + errorCount++; + errorMsg.append("第").append(i + 1).append("行: ").append(e.getMessage()).append("; "); + log.error("导入维保项目第{}行失败: {}", i + 1, e.getMessage()); + } + } + workbook.close(); + if (errorCount > 0) { + throw new RuntimeException("导入完成,成功" + successCount + "条,失败" + errorCount + "条。错误信息:" + errorMsg.toString()); + } + log.info("维保项目导入完成,成功{}条", successCount); + } catch (IOException e) { + log.error("读取Excel文件失败", e); + throw new RuntimeException("读取Excel文件失败: " + e.getMessage()); + } catch (Exception e) { + log.error("导入维保项目失败", e); + throw new RuntimeException(e.getMessage()); + } + } + + /** + * 获取单元格值 + */ + private String getCellValue(XSSFCell cell) { + if (cell == null) { + return ""; + } + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue().trim(); + case NUMERIC: + if (isCellDateFormatted(cell)) { + return cell.getDateCellValue().toString(); + } else { + double numericValue = cell.getNumericCellValue(); + if (numericValue == Math.floor(numericValue)) { + return String.valueOf((long) numericValue); + } else { + return String.valueOf(numericValue); + } + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + case FORMULA: + try { + return String.valueOf(cell.getNumericCellValue()); + } catch (Exception e) { + return cell.getStringCellValue(); + } + default: + return ""; + } + } }