|
|
|
@ -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<EamPropertiesItemData> 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<EamPropertiesItemData> 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 ""; |
|
|
|
} |
|
|
|
} |
|
|
|
} |