Browse Source

feat(eam): 添加维保模板导入功能

- 实现下载维保模板导入模板接口,支持Excel格式
- 添加批量导入维保模板功能,支持模板和项目关联
- 实现维保项目编码验证,确保引用的项目存在
- 支持维保模板的新增和更新操作
- 实现导入过程中的数据验证和错误处理
- 添加导入日志记录和进度反馈功能
master
qiankanghui 3 days ago
parent
commit
8d0029843f
  1. 111
      src/main/java/com/xujie/sys/modules/pms/controller/EamController.java
  2. 12
      src/main/java/com/xujie/sys/modules/pms/service/EamService.java
  3. 222
      src/main/java/com/xujie/sys/modules/pms/service/Impl/EamServiceImpl.java

111
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<ByteArrayResource> 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());
}
}
} }

12
src/main/java/com/xujie/sys/modules/pms/service/EamService.java

@ -1268,4 +1268,16 @@ public interface EamService {
* @return void * @return void
*/ */
void uploadEamMaintenanceItemExcel(MultipartFile file, String createBy, String site, String buNo); 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);
} }

222
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.setUpdateBy(createBy);
modelData.setCheckType(checkType); modelData.setCheckType(checkType);
// 检查模板是否已存在
// 处理点检项目第4-8列点检项目编码1-5
List<String> 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<EamPropertiesItemData> existItems = eamDao.checkEamPropertiesItem(itemQuery);
if (existItems == null || existItems.isEmpty()) {
throw new RuntimeException("点检项目编码[" + itemNo + "]不存在,请先导入该点检项目");
}
}
}
// 验证通过后再保存或更新模板
List<EamPropertiesModelHeaderData> existModels = eamDao.eamPropertiesModelSearch(modelData); List<EamPropertiesModelHeaderData> existModels = eamDao.eamPropertiesModelSearch(modelData);
boolean isNewTemplate = true; boolean isNewTemplate = true;
if (existModels != null && !existModels.isEmpty()) { if (existModels != null && !existModels.isEmpty()) {
@ -4821,7 +4848,147 @@ public class EamServiceImpl implements EamService {
eamDao.editEamPropertiesModel(modelData); 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<EamPropertiesItemData> 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<String> itemNos = new ArrayList<>(); List<String> itemNos = new ArrayList<>();
for (int j = 4; j <= 8; j++) { for (int j = 4; j <= 8; j++) {
String itemNo = getCellValue(row.getCell(j)); String itemNo = getCellValue(row.getCell(j));
@ -4831,28 +4998,53 @@ public class EamServiceImpl implements EamService {
} }
} }
// 去重移除重复的项目编码
Set<String> uniqueItemNos = new LinkedHashSet<>(itemNos);
itemNos = new ArrayList<>(uniqueItemNos);
// 先验证所有维保项目是否存在在保存模板之前
if (!itemNos.isEmpty()) { if (!itemNos.isEmpty()) {
// 验证每个点检项目是否存在
for (String itemNo : itemNos) { for (String itemNo : itemNos) {
EamPropertiesItemData itemQuery = new EamPropertiesItemData(); EamPropertiesItemData itemQuery = new EamPropertiesItemData();
itemQuery.setSite(site); itemQuery.setSite(site);
itemQuery.setBuNo(buNo); itemQuery.setBuNo(buNo);
itemQuery.setItemNo(itemNo); itemQuery.setItemNo(itemNo);
itemQuery.setItemType("A");
itemQuery.setItemType("B");
itemQuery.setCheckType(checkType); itemQuery.setCheckType(checkType);
List<EamPropertiesItemData> existItems = eamDao.checkEamPropertiesItem(itemQuery); List<EamPropertiesItemData> existItems = eamDao.checkEamPropertiesItem(itemQuery);
if (existItems == null || existItems.isEmpty()) { if (existItems == null || existItems.isEmpty()) {
throw new RuntimeException("点检项目编码[" + itemNo + "]不存在,请先导入该点检项目");
throw new RuntimeException("维保项目编码[" + itemNo + "]不存在,请先导入该维保项目");
}
} }
} }
// 先删除该模板下的所有项目关联
// 验证通过后再保存或更新模板
List<EamPropertiesModelHeaderData> 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(); EamPropertiesModelDetailData deleteData = new EamPropertiesModelDetailData();
deleteData.setSite(site); deleteData.setSite(site);
deleteData.setBuNo(buNo); deleteData.setBuNo(buNo);
deleteData.setCodeNo(codeNo); deleteData.setCodeNo(codeNo);
deleteData.setFunctionType("A");
deleteData.setFunctionType("B");
eamDao.deleteModalDetails(deleteData); eamDao.deleteModalDetails(deleteData);
// 重新关联项目 // 重新关联项目
@ -4864,8 +5056,8 @@ public class EamServiceImpl implements EamService {
itemData.setCodeNo(codeNo); itemData.setCodeNo(codeNo);
itemData.setCodeDesc(codeDesc); itemData.setCodeDesc(codeDesc);
itemData.setItemNo(itemNo); itemData.setItemNo(itemNo);
itemData.setItemType("A");
itemData.setFunctionType("A");
itemData.setItemType("B");
itemData.setFunctionType("B");
itemData.setUserId(createBy); itemData.setUserId(createBy);
itemData.setCheckType(checkType); itemData.setCheckType(checkType);
itemList.add(itemData); itemList.add(itemData);
@ -4877,9 +5069,9 @@ public class EamServiceImpl implements EamService {
saveData.setBuNo(buNo); saveData.setBuNo(buNo);
saveData.setCodeNo(codeNo); saveData.setCodeNo(codeNo);
saveData.setCodeDesc(codeDesc); saveData.setCodeDesc(codeDesc);
saveData.setFunctionType("A");
saveData.setFunctionType("B");
saveData.setItemList(itemList); saveData.setItemList(itemList);
saveData.setItemType("A");
saveData.setItemType("B");
saveData.setUserId(createBy); saveData.setUserId(createBy);
saveData.setCheckType(checkType); saveData.setCheckType(checkType);
@ -4887,12 +5079,12 @@ public class EamServiceImpl implements EamService {
} }
successCount++; successCount++;
log.info("成功导入点检模板: {}, 关联{}个项目", codeNo, itemNos.size());
log.info("成功导入维保模板: {}, 关联{}个项目", codeNo, itemNos.size());
} catch (Exception e) { } catch (Exception e) {
errorCount++; errorCount++;
errorMsg.append("第").append(i + 1).append("行: ").append(e.getMessage()).append("; "); 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()); throw new RuntimeException("导入完成,成功" + successCount + "条,失败" + errorCount + "条。错误信息:" + errorMsg.toString());
} }
log.info("点检模板导入完成,成功{}条", successCount);
log.info("维保模板导入完成,成功{}条", successCount);
} catch (IOException e) { } catch (IOException e) {
log.error("读取Excel文件失败", e); log.error("读取Excel文件失败", e);
throw new RuntimeException("读取Excel文件失败: " + e.getMessage()); throw new RuntimeException("读取Excel文件失败: " + e.getMessage());
} catch (Exception e) { } catch (Exception e) {
log.error("导入点检模板失败", e);
log.error("导入维保模板失败", e);
throw new RuntimeException(e.getMessage()); throw new RuntimeException(e.getMessage());
} }
} }

Loading…
Cancel
Save