From 8d0029843fe544c9ba26702ed7c058dbe207fb88 Mon Sep 17 00:00:00 2001 From: qiankanghui Date: Thu, 9 Jul 2026 15:56:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(eam):=20=E6=B7=BB=E5=8A=A0=E7=BB=B4?= =?UTF-8?q?=E4=BF=9D=E6=A8=A1=E6=9D=BF=E5=AF=BC=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现下载维保模板导入模板接口,支持Excel格式 - 添加批量导入维保模板功能,支持模板和项目关联 - 实现维保项目编码验证,确保引用的项目存在 - 支持维保模板的新增和更新操作 - 实现导入过程中的数据验证和错误处理 - 添加导入日志记录和进度反馈功能 --- .../modules/pms/controller/EamController.java | 111 +++++++++ .../sys/modules/pms/service/EamService.java | 12 + .../pms/service/Impl/EamServiceImpl.java | 222 ++++++++++++++++-- 3 files changed, 330 insertions(+), 15 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 4497a734..e59d49db 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 @@ -2947,4 +2947,115 @@ public class EamController { } } + /** + * @Description 下载维保模板导入模板 + * @Title downloadEamMaintenanceModelTemplate + * @date 2026/7/9 + */ + @GetMapping("/downloadEamMaintenanceModelTemplate") + public ResponseEntity downloadEamMaintenanceModelTemplate() { + 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 = { + "维保模板编码", "维保模板名称", "部门", "在用", + "维保项目编码1", "维保项目编码2", "维保项目编码3", + "维保项目编码4", "维保项目编码5" + }; + 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("设备日常保养模板"); + dataRow1.createCell(2).setCellValue("R022"); + dataRow1.createCell(3).setCellValue("Y"); + dataRow1.createCell(4).setCellValue("ITEM001"); + dataRow1.createCell(5).setCellValue("ITEM002"); + dataRow1.createCell(6).setCellValue(""); + dataRow1.createCell(7).setCellValue(""); + dataRow1.createCell(8).setCellValue(""); + + // 设置列宽 + for (int i = 0; i < headers.length; i++) { + if (i == 0) { + sheet.setColumnWidth(i, 18 * 256); // 维保模板编码 + } else if (i == 1) { + sheet.setColumnWidth(i, 25 * 256); // 维保模板名称 + } else if (i == 2) { + sheet.setColumnWidth(i, 12 * 256); // 部门 + } else if (i == 3) { + sheet.setColumnWidth(i, 10 * 256); // 在用 + } else { + sheet.setColumnWidth(i, 15 * 256); // 维保项目编码1-5 + } + } + + // 写入到字节数组 + workbook.write(outputStream); + } + + 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 uploadEamMaintenanceModelExcel + * @date 2026/7/9 + */ + @PostMapping("/uploadEamMaintenanceModelExcel") + public R uploadEamMaintenanceModelExcel(@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.uploadEamMaintenanceModelExcel(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 56aeec2a..8ac3341c 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 @@ -1268,4 +1268,16 @@ public interface EamService { * @return void */ void uploadEamMaintenanceItemExcel(MultipartFile file, String createBy, String site, String buNo); + + /** + * @Description 批量导入维保模板Excel(包含模板和项目关联) + * @Title uploadEamMaintenanceModelExcel + * @param file + * @param createBy + * @param site + * @param buNo + * @date 2026/7/9 + * @return void + */ + void uploadEamMaintenanceModelExcel(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 bc8b77e5..decc895d 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 @@ -4802,7 +4802,34 @@ public class EamServiceImpl implements EamService { modelData.setUpdateBy(createBy); modelData.setCheckType(checkType); - // 检查模板是否已存在 + // 处理点检项目(第4-8列:点检项目编码1-5) + List itemNos = new ArrayList<>(); + for (int j = 4; j <= 8; j++) { + String itemNo = getCellValue(row.getCell(j)); + if (!StringUtils.isEmpty(itemNo)) { + itemNo = itemNo.toUpperCase(); + itemNos.add(itemNo); + } + } + + // 先验证所有点检项目是否存在(在保存模板之前) + if (!itemNos.isEmpty()) { + for (String itemNo : itemNos) { + EamPropertiesItemData itemQuery = new EamPropertiesItemData(); + itemQuery.setSite(site); + itemQuery.setBuNo(buNo); + itemQuery.setItemNo(itemNo); + itemQuery.setItemType("A"); + itemQuery.setCheckType(checkType); + + List existItems = eamDao.checkEamPropertiesItem(itemQuery); + if (existItems == null || existItems.isEmpty()) { + throw new RuntimeException("点检项目编码[" + itemNo + "]不存在,请先导入该点检项目"); + } + } + } + + // 验证通过后,再保存或更新模板 List existModels = eamDao.eamPropertiesModelSearch(modelData); boolean isNewTemplate = true; if (existModels != null && !existModels.isEmpty()) { @@ -4821,7 +4848,147 @@ public class EamServiceImpl implements EamService { eamDao.editEamPropertiesModel(modelData); } - // 处理点检项目(第4-8列:点检项目编码1-5) + // 关联项目(只有在有项目时才处理) + if (!itemNos.isEmpty()) { + + // 先删除该模板下的所有项目关联 + EamPropertiesModelDetailData deleteData = new EamPropertiesModelDetailData(); + deleteData.setSite(site); + deleteData.setBuNo(buNo); + deleteData.setCodeNo(codeNo); + deleteData.setFunctionType("A"); + eamDao.deleteModalDetails(deleteData); + + // 重新关联项目 + List itemList = new ArrayList<>(); + for (String itemNo : itemNos) { + EamPropertiesItemData itemData = new EamPropertiesItemData(); + itemData.setSite(site); + itemData.setBuNo(buNo); + itemData.setCodeNo(codeNo); + itemData.setCodeDesc(codeDesc); + itemData.setItemNo(itemNo); + itemData.setItemType("A"); + itemData.setFunctionType("A"); + itemData.setUserId(createBy); + itemData.setCheckType(checkType); + itemList.add(itemData); + } + + // 批量保存项目关联 + EamPropertiesModelHeaderData saveData = new EamPropertiesModelHeaderData(); + saveData.setSite(site); + saveData.setBuNo(buNo); + saveData.setCodeNo(codeNo); + saveData.setCodeDesc(codeDesc); + saveData.setFunctionType("A"); + saveData.setItemList(itemList); + saveData.setItemType("A"); + saveData.setUserId(createBy); + saveData.setCheckType(checkType); + + eamDao.saveModalDetails(saveData); + } + + successCount++; + log.info("成功导入点检模板: {}, 关联{}个项目", codeNo, itemNos.size()); + + } 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()); + } + } + + @Override + public void uploadEamMaintenanceModelExcel(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 { + // 第0列:维保模板编码 + String codeNo = getCellValue(row.getCell(0)); + if (StringUtils.isEmpty(codeNo)) { + throw new RuntimeException("维保模板编码不能为空"); + } + codeNo = codeNo.toUpperCase(); + + // 第1列:维保模板名称 + String codeDesc = getCellValue(row.getCell(1)); + if (StringUtils.isEmpty(codeDesc)) { + throw new RuntimeException("维保模板名称不能为空"); + } + + // 第2列:部门 + String checkType = getCellValue(row.getCell(2)); + if (StringUtils.isEmpty(checkType)) { + throw new RuntimeException("部门不能为空"); + } + checkType = convertCheckType(checkType); + + // 第3列:在用 + String active = getCellValue(row.getCell(3)); + if (StringUtils.isEmpty(active)) { + active = "Y"; + } + if (!"Y".equals(active) && !"N".equals(active)) { + throw new RuntimeException("在用只能是Y或N"); + } + + // 创建或更新维保模板 + EamPropertiesModelHeaderData modelData = new EamPropertiesModelHeaderData(); + modelData.setSite(site); + modelData.setBuNo(buNo); + modelData.setCodeNo(codeNo); + modelData.setCodeDesc(codeDesc); + modelData.setActive(active); + modelData.setFunctionType("B"); + modelData.setUserId(createBy); + modelData.setCreatedBy(createBy); + modelData.setUpdateBy(createBy); + modelData.setCheckType(checkType); + + // 处理维保项目(第4-8列:维保项目编码1-5) List itemNos = new ArrayList<>(); for (int j = 4; j <= 8; j++) { String itemNo = getCellValue(row.getCell(j)); @@ -4830,29 +4997,54 @@ public class EamServiceImpl implements EamService { itemNos.add(itemNo); } } + + // 去重:移除重复的项目编码 + Set uniqueItemNos = new LinkedHashSet<>(itemNos); + itemNos = new ArrayList<>(uniqueItemNos); + // 先验证所有维保项目是否存在(在保存模板之前) if (!itemNos.isEmpty()) { - // 验证每个点检项目是否存在 for (String itemNo : itemNos) { EamPropertiesItemData itemQuery = new EamPropertiesItemData(); itemQuery.setSite(site); itemQuery.setBuNo(buNo); itemQuery.setItemNo(itemNo); - itemQuery.setItemType("A"); + itemQuery.setItemType("B"); itemQuery.setCheckType(checkType); List existItems = eamDao.checkEamPropertiesItem(itemQuery); if (existItems == null || existItems.isEmpty()) { - throw new RuntimeException("点检项目编码[" + itemNo + "]不存在,请先导入该点检项目"); + throw new RuntimeException("维保项目编码[" + itemNo + "]不存在,请先导入该维保项目"); } } + } - // 先删除该模板下的所有项目关联 + // 验证通过后,再保存或更新模板 + List existModels = eamDao.eamPropertiesModelSearch(modelData); + boolean isNewTemplate = true; + if (existModels != null && !existModels.isEmpty()) { + // 模板已存在,使用现有模板的ID进行更新 + modelData.setFlag("2"); // 更新标志 + isNewTemplate = false; + log.info("维保模板已存在,将更新: {}", codeNo); + } else { + modelData.setFlag("1"); // 新增标志 + } + + // 保存或更新模板 + if ("1".equals(modelData.getFlag())) { + eamDao.saveEamPropertiesModel(modelData); + } else { + eamDao.editEamPropertiesModel(modelData); + } + + // 关联项目(只有在有项目时才处理) + if (!itemNos.isEmpty()) { EamPropertiesModelDetailData deleteData = new EamPropertiesModelDetailData(); deleteData.setSite(site); deleteData.setBuNo(buNo); deleteData.setCodeNo(codeNo); - deleteData.setFunctionType("A"); + deleteData.setFunctionType("B"); eamDao.deleteModalDetails(deleteData); // 重新关联项目 @@ -4864,8 +5056,8 @@ public class EamServiceImpl implements EamService { itemData.setCodeNo(codeNo); itemData.setCodeDesc(codeDesc); itemData.setItemNo(itemNo); - itemData.setItemType("A"); - itemData.setFunctionType("A"); + itemData.setItemType("B"); + itemData.setFunctionType("B"); itemData.setUserId(createBy); itemData.setCheckType(checkType); itemList.add(itemData); @@ -4877,9 +5069,9 @@ public class EamServiceImpl implements EamService { saveData.setBuNo(buNo); saveData.setCodeNo(codeNo); saveData.setCodeDesc(codeDesc); - saveData.setFunctionType("A"); + saveData.setFunctionType("B"); saveData.setItemList(itemList); - saveData.setItemType("A"); + saveData.setItemType("B"); saveData.setUserId(createBy); saveData.setCheckType(checkType); @@ -4887,12 +5079,12 @@ public class EamServiceImpl implements EamService { } successCount++; - log.info("成功导入点检模板: {}, 关联{}个项目", codeNo, itemNos.size()); + log.info("成功导入维保模板: {}, 关联{}个项目", codeNo, itemNos.size()); } catch (Exception e) { errorCount++; errorMsg.append("第").append(i + 1).append("行: ").append(e.getMessage()).append("; "); - log.error("导入点检模板第{}行失败: {}", i + 1, e.getMessage()); + log.error("导入维保模板第{}行失败: {}", i + 1, e.getMessage()); } } @@ -4902,12 +5094,12 @@ public class EamServiceImpl implements EamService { throw new RuntimeException("导入完成,成功" + successCount + "条,失败" + errorCount + "条。错误信息:" + errorMsg.toString()); } - log.info("点检模板导入完成,成功{}条", successCount); + log.info("维保模板导入完成,成功{}条", successCount); } catch (IOException e) { log.error("读取Excel文件失败", e); throw new RuntimeException("读取Excel文件失败: " + e.getMessage()); } catch (Exception e) { - log.error("导入点检模板失败", e); + log.error("导入维保模板失败", e); throw new RuntimeException(e.getMessage()); } }