diff --git a/blade-common/src/main/java/org/springblade/common/excel/ImportFailureExcelUtil.java b/blade-common/src/main/java/org/springblade/common/excel/ImportFailureExcelUtil.java index c529a25..53771af 100644 --- a/blade-common/src/main/java/org/springblade/common/excel/ImportFailureExcelUtil.java +++ b/blade-common/src/main/java/org/springblade/common/excel/ImportFailureExcelUtil.java @@ -57,6 +57,27 @@ import java.util.Objects; */ public class ImportFailureExcelUtil { + public static String formatErrorMessage(int rowNumber, List validationErrors) { + StringBuilder errorMessage = new StringBuilder("第").append(rowNumber).append("行:"); + for (int index = 0; index < validationErrors.size(); index++) { + if (index > 0) { + errorMessage.append(System.lineSeparator()); + } + errorMessage.append(index + 1).append(". ").append(validationErrors.get(index)); + } + return errorMessage.toString(); + } + + public static void addValidationError(List validationErrors, boolean invalid, String message) { + if (invalid && message != null && !message.isBlank() && !validationErrors.contains(message)) { + validationErrors.add(message); + } + } + + public static void addLengthValidationError(List validationErrors, String value, int maxLength, String message) { + addValidationError(validationErrors, value != null && value.length() > maxLength, message); + } + private static final String FAILURE_REASON = "导入失败原因"; private static final String ERROR_MESSAGE_FIELD = "errorMessage"; private static final String FAILURE_REASON_FIELD = "failureReason"; @@ -244,6 +265,7 @@ public class ImportFailureExcelUtil { Font font = workbook.createFont(); font.setColor(IndexedColors.RED.getIndex()); newStyle.setFont(font); + newStyle.setWrapText(true); return newStyle; }); cell.setCellStyle(redStyle); diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/excel/AirportMasterExcel.java b/blade-service/blade-system/src/main/java/org/springblade/system/excel/AirportMasterExcel.java index b72d4d5..4c2c095 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/excel/AirportMasterExcel.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/excel/AirportMasterExcel.java @@ -100,7 +100,7 @@ public class AirportMasterExcel implements Serializable { @ExcelProperty("备注") private String remark; - @ExcelProperty + @ExcelIgnore private String errorMessage; } diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/excel/PortTerminalExcel.java b/blade-service/blade-system/src/main/java/org/springblade/system/excel/PortTerminalExcel.java index 6e394a2..fa9f4c6 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/excel/PortTerminalExcel.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/excel/PortTerminalExcel.java @@ -53,13 +53,13 @@ public class PortTerminalExcel implements Serializable { @ExcelIgnore private Long id; - @ExcelProperty("编码") + @ExcelProperty("*编码") private String code; - @ExcelProperty("港口/码头名称") + @ExcelProperty("*港口/码头名称") private String name; - @ExcelProperty("类型") + @ExcelProperty("*类型") private String category; @ExcelProperty("上级港口") @@ -68,13 +68,13 @@ public class PortTerminalExcel implements Serializable { @ExcelProperty("上级港口编码") private String parentCode; - @ExcelProperty("国家") + @ExcelProperty("*国家") private String country; - @ExcelProperty("城市") + @ExcelProperty("*城市") private String city; - @ExcelProperty("区县") + @ExcelProperty("*区县") private String districtName; @ExcelProperty("行政区划编码") @@ -83,24 +83,24 @@ public class PortTerminalExcel implements Serializable { @ExcelProperty("详细地址") private String detailAddress; - @ExcelProperty("经度") + @ExcelProperty("*经度") @NumberFormat("0.000000") private BigDecimal longitude; - @ExcelProperty("纬度") + @ExcelProperty("*纬度") @NumberFormat("0.000000") private BigDecimal latitude; - @ExcelProperty("数据来源") + @ExcelIgnore private String dataSource; - @ExcelProperty("启停状态") + @ExcelIgnore private String statusName; @ExcelProperty("备注") private String remark; - @ExcelProperty + @ExcelIgnore private String errorMessage; } diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/excel/RailwayStationExcel.java b/blade-service/blade-system/src/main/java/org/springblade/system/excel/RailwayStationExcel.java index d4915b4..0e1cd27 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/excel/RailwayStationExcel.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/excel/RailwayStationExcel.java @@ -96,7 +96,7 @@ public class RailwayStationExcel implements Serializable { @ExcelProperty("备注") private String remark; - @ExcelProperty + @ExcelIgnore private String errorMessage; } diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/AirportMasterServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/AirportMasterServiceImpl.java index 53dc0a5..6270287 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/AirportMasterServiceImpl.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/AirportMasterServiceImpl.java @@ -43,12 +43,15 @@ import org.springblade.system.service.IAirportMasterService; import org.springblade.system.service.IRegionService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; @@ -124,24 +127,184 @@ public class AirportMasterServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List airportMasterList = new ArrayList<>(); + Map iataCodeCountMap = buildImportValueCountMap(data.stream() + .map(excel -> trimToEmpty(excel.getIataCode()).toUpperCase(Locale.ROOT)) + .toList()); + Map icaoCodeCountMap = buildImportValueCountMap(data.stream() + .map(excel -> trimToEmpty(excel.getIcaoCode()).toUpperCase(Locale.ROOT)) + .toList()); for (int index = 0; index < data.size(); index++) { AirportMasterExcel excel = data.get(index); + AirportMaster airportMaster = Objects.requireNonNull(BeanUtil.copyProperties(excel, AirportMaster.class)); + airportMaster.setDataSource(SOURCE_BATCH); + airportMaster.setStatus(STATUS_ENABLED); + normalizeImportAirportMaster(airportMaster); + List validationErrors = validateImportAirportMaster(airportMaster, iataCodeCountMap, icaoCodeCountMap); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(formatImportErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } try { - AirportMaster airportMaster = Objects.requireNonNull(BeanUtil.copyProperties(excel, AirportMaster.class)); - airportMaster.setDataSource(SOURCE_BATCH); - airportMaster.setStatus(STATUS_ENABLED); prepare(airportMaster, SOURCE_BATCH); validate(airportMaster); - save(airportMaster); + airportMasterList.add(airportMaster); } catch (Exception exception) { String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; - excel.setErrorMessage("第" + (index + 2) + "行:" + message); + excel.setErrorMessage(formatImportErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (AirportMaster airportMaster : airportMasterList) { + if (!save(airportMaster)) { + throw new ServiceException("空港机场保存失败"); + } + } return errorList; } + private Map buildImportValueCountMap(List values) { + Map valueCountMap = new HashMap<>(); + for (String value : values) { + if (Func.isNotEmpty(value)) { + valueCountMap.merge(value, 1, Integer::sum); + } + } + return valueCountMap; + } + + private void normalizeImportAirportMaster(AirportMaster airportMaster) { + airportMaster.setIataCode(trimToEmpty(airportMaster.getIataCode()).toUpperCase(Locale.ROOT)); + airportMaster.setCode(CODE_PREFIX + airportMaster.getIataCode()); + airportMaster.setIcaoCode(trimToEmpty(airportMaster.getIcaoCode()).toUpperCase(Locale.ROOT)); + airportMaster.setName(trimToEmpty(airportMaster.getName())); + airportMaster.setShortName(trimToNull(airportMaster.getShortName())); + airportMaster.setProvinceCode(trimToNull(airportMaster.getProvinceCode())); + airportMaster.setProvinceName(trimToNull(airportMaster.getProvinceName())); + airportMaster.setCityCode(trimToNull(airportMaster.getCityCode())); + airportMaster.setCityName(trimToNull(airportMaster.getCityName())); + airportMaster.setDistrictCode(trimToNull(airportMaster.getDistrictCode())); + airportMaster.setDistrictName(trimToNull(airportMaster.getDistrictName())); + airportMaster.setRegionCode(trimToNull(airportMaster.getRegionCode())); + if (Func.isEmpty(airportMaster.getDistrictCode()) && Func.isNotEmpty(airportMaster.getRegionCode())) { + airportMaster.setDistrictCode(airportMaster.getRegionCode()); + } + airportMaster.setDetailAddress(trimToNull(airportMaster.getDetailAddress())); + airportMaster.setRemark(trimToNull(airportMaster.getRemark())); + } + + private List validateImportAirportMaster(AirportMaster airportMaster, + Map iataCodeCountMap, Map icaoCodeCountMap) { + List validationErrors = new ArrayList<>(); + if (Func.isEmpty(airportMaster.getIataCode())) { + addValidationError(validationErrors, "IATA编码不能为空"); + } else { + if (!IATA_CODE_PATTERN.matcher(airportMaster.getIataCode()).matches()) { + addValidationError(validationErrors, "IATA编码为3位大写字母"); + } + if (iataCodeCountMap.getOrDefault(airportMaster.getIataCode(), 0) > 1) { + addValidationError(validationErrors, "IATA编码在本次导入中重复"); + } + validateImportUnique(AirportMaster::getIataCode, airportMaster.getIataCode(), "该IATA编码已存在", validationErrors); + validateImportUnique(AirportMaster::getCode, airportMaster.getCode(), "该编码已存在", validationErrors); + } + if (Func.isEmpty(airportMaster.getIcaoCode())) { + addValidationError(validationErrors, "ICAO代码不能为空"); + } else { + if (!ICAO_CODE_PATTERN.matcher(airportMaster.getIcaoCode()).matches()) { + addValidationError(validationErrors, "ICAO代码为4位大写字母"); + } + if (icaoCodeCountMap.getOrDefault(airportMaster.getIcaoCode(), 0) > 1) { + addValidationError(validationErrors, "ICAO代码在本次导入中重复"); + } + validateImportUnique(AirportMaster::getIcaoCode, airportMaster.getIcaoCode(), "该ICAO代码已存在", validationErrors); + } + if (Func.isEmpty(airportMaster.getName())) { + addValidationError(validationErrors, "机场标准名称不能为空"); + } + validateImportLength(airportMaster.getCode(), CODE_MAX_LENGTH, "编码不能超过20字", validationErrors); + validateImportLength(airportMaster.getName(), NAME_MAX_LENGTH, "机场标准名称不能超过100字", validationErrors); + validateImportLength(airportMaster.getShortName(), SHORT_NAME_MAX_LENGTH, "机场简称不能超过100字", validationErrors); + validateImportLength(airportMaster.getProvinceName(), REGION_NAME_MAX_LENGTH, "所属省份不能超过128字", validationErrors); + validateImportLength(airportMaster.getCityName(), REGION_NAME_MAX_LENGTH, "所属城市不能超过128字", validationErrors); + validateImportLength(airportMaster.getDistrictName(), REGION_NAME_MAX_LENGTH, "所属区县不能超过128字", validationErrors); + validateImportLength(airportMaster.getRegionCode(), REGION_CODE_MAX_LENGTH, "行政区划编号不能超过32字", validationErrors); + validateImportLength(airportMaster.getDetailAddress(), DETAIL_ADDRESS_MAX_LENGTH, "详细地址不能超过255字", validationErrors); + validateImportLength(airportMaster.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字", validationErrors); + if (Func.isEmpty(airportMaster.getLongitude())) { + addValidationError(validationErrors, "经度不能为空"); + } else if (!validRange(airportMaster.getLongitude(), MIN_LONGITUDE, MAX_LONGITUDE)) { + addValidationError(validationErrors, "经度范围为 -180 到 180"); + } + if (Func.isEmpty(airportMaster.getLatitude())) { + addValidationError(validationErrors, "纬度不能为空"); + } else if (!validRange(airportMaster.getLatitude(), MIN_LATITUDE, MAX_LATITUDE)) { + addValidationError(validationErrors, "纬度范围为 -90 到 90"); + } + validateImportAirportRegion(airportMaster, validationErrors); + return validationErrors; + } + + private void validateImportAirportRegion(AirportMaster airportMaster, List validationErrors) { + boolean provinceMissing = Func.isEmpty(airportMaster.getProvinceCode()) && Func.isEmpty(airportMaster.getProvinceName()); + boolean cityMissing = Func.isEmpty(airportMaster.getCityCode()) && Func.isEmpty(airportMaster.getCityName()); + boolean districtMissing = Func.isEmpty(airportMaster.getDistrictCode()) && Func.isEmpty(airportMaster.getDistrictName()); + if (provinceMissing) { + addValidationError(validationErrors, "所属省份不能为空"); + } + if (cityMissing) { + addValidationError(validationErrors, "所属城市不能为空"); + } + if (districtMissing) { + addValidationError(validationErrors, "所属区县不能为空"); + } + if (provinceMissing || cityMissing || districtMissing) { + return; + } + try { + fillRegion(airportMaster); + } catch (ServiceException exception) { + addValidationError(validationErrors, exception.getMessage()); + } + } + + private void validateImportUnique(com.baomidou.mybatisplus.core.toolkit.support.SFunction column, + String value, String message, List validationErrors) { + if (count(Wrappers.lambdaQuery() + .eq(column, value) + .eq(AirportMaster::getIsDeleted, 0)) > 0L) { + addValidationError(validationErrors, message); + } + } + + private void validateImportLength(String value, int maxLength, String message, List validationErrors) { + if (Func.isNotEmpty(value) && value.length() > maxLength) { + addValidationError(validationErrors, message); + } + } + + private void addValidationError(List validationErrors, String message) { + if (Func.isNotEmpty(message) && !validationErrors.contains(message)) { + validationErrors.add(message); + } + } + + private String formatImportErrorMessage(int rowNumber, List validationErrors) { + StringBuilder errorMessage = new StringBuilder("第").append(rowNumber).append("行:"); + for (int index = 0; index < validationErrors.size(); index++) { + if (index > 0) { + errorMessage.append(System.lineSeparator()); + } + errorMessage.append(index + 1).append(". ").append(validationErrors.get(index)); + } + return errorMessage.toString(); + } + @Override public List exportAirportMaster(Wrapper queryWrapper) { List airportMasterList = list(queryWrapper); diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/PortTerminalServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/PortTerminalServiceImpl.java index 07aaf8a..14d485c 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/PortTerminalServiceImpl.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/PortTerminalServiceImpl.java @@ -43,12 +43,15 @@ import org.springblade.system.service.IPortTerminalService; import org.springblade.system.service.IRegionService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; @@ -134,24 +137,187 @@ public class PortTerminalServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List portTerminalList = new ArrayList<>(); + Map codeCountMap = buildImportCodeCountMap(data); for (int index = 0; index < data.size(); index++) { PortTerminalExcel excel = data.get(index); + PortTerminal portTerminal = Objects.requireNonNull(BeanUtil.copyProperties(excel, PortTerminal.class)); + portTerminal.setDataSource(SOURCE_BATCH); + portTerminal.setStatus(STATUS_ENABLED); + normalizeImportPortTerminal(portTerminal); + List validationErrors = validateImportPortTerminal(portTerminal, codeCountMap); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(formatImportErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } try { - PortTerminal portTerminal = Objects.requireNonNull(BeanUtil.copyProperties(excel, PortTerminal.class)); - portTerminal.setDataSource(SOURCE_BATCH); - portTerminal.setStatus(STATUS_ENABLED); prepare(portTerminal, SOURCE_BATCH); validate(portTerminal); - save(portTerminal); + portTerminalList.add(portTerminal); } catch (Exception exception) { String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; - excel.setErrorMessage("第" + (index + 2) + "行:" + message); + excel.setErrorMessage(formatImportErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (PortTerminal portTerminal : portTerminalList) { + if (!save(portTerminal)) { + throw new ServiceException("港口码头保存失败"); + } + } return errorList; } + private String formatImportErrorMessage(int rowNumber, List validationErrors) { + StringBuilder errorMessage = new StringBuilder("第").append(rowNumber).append("行:"); + for (int index = 0; index < validationErrors.size(); index++) { + if (index > 0) { + errorMessage.append(System.lineSeparator()); + } + errorMessage.append(index + 1).append(". ").append(validationErrors.get(index)); + } + return errorMessage.toString(); + } + + private Map buildImportCodeCountMap(List data) { + Map codeCountMap = new HashMap<>(); + for (PortTerminalExcel excel : data) { + String code = trimToEmpty(excel.getCode()).toUpperCase(Locale.ROOT); + if (Func.isNotEmpty(code)) { + codeCountMap.merge(code, 1, Integer::sum); + } + } + return codeCountMap; + } + + private void normalizeImportPortTerminal(PortTerminal portTerminal) { + portTerminal.setCode(trimToEmpty(portTerminal.getCode()).toUpperCase(Locale.ROOT)); + portTerminal.setCategory(trimToEmpty(portTerminal.getCategory())); + portTerminal.setName(trimToEmpty(portTerminal.getName())); + portTerminal.setParentCode(trimToNull(portTerminal.getParentCode())); + if (Func.isNotEmpty(portTerminal.getParentCode())) { + portTerminal.setParentCode(portTerminal.getParentCode().toUpperCase(Locale.ROOT)); + } + portTerminal.setParentName(trimToNull(portTerminal.getParentName())); + portTerminal.setCountry(trimToEmpty(portTerminal.getCountry())); + portTerminal.setCity(trimToEmpty(portTerminal.getCity())); + portTerminal.setDistrictCode(trimToNull(portTerminal.getDistrictCode())); + portTerminal.setDistrictName(trimToNull(portTerminal.getDistrictName())); + portTerminal.setRegionCode(trimToNull(portTerminal.getRegionCode())); + if (Func.isEmpty(portTerminal.getDistrictCode()) && Func.isNotEmpty(portTerminal.getRegionCode())) { + portTerminal.setDistrictCode(portTerminal.getRegionCode()); + } + portTerminal.setDetailAddress(trimToNull(portTerminal.getDetailAddress())); + portTerminal.setRemark(trimToNull(portTerminal.getRemark())); + } + + private List validateImportPortTerminal(PortTerminal portTerminal, Map codeCountMap) { + List validationErrors = new ArrayList<>(); + if (!CATEGORY_PORT.equals(portTerminal.getCategory()) && !CATEGORY_TERMINAL.equals(portTerminal.getCategory())) { + addValidationError(validationErrors, "类型只能为港口或码头"); + } + if (Func.isEmpty(portTerminal.getCode())) { + addValidationError(validationErrors, "编码不能为空"); + } else { + validateImportLength(portTerminal.getCode(), CODE_MAX_LENGTH, "编码不能超过30字", validationErrors); + if (CATEGORY_PORT.equals(portTerminal.getCategory()) && !PORT_CODE_PATTERN.matcher(portTerminal.getCode()).matches()) { + addValidationError(validationErrors, "港口编码为5位大写字母"); + } + if (CATEGORY_TERMINAL.equals(portTerminal.getCategory()) && !TERMINAL_CODE_PATTERN.matcher(portTerminal.getCode()).matches()) { + addValidationError(validationErrors, "码头编码格式为港口编码-码头标识"); + } + if (codeCountMap.getOrDefault(portTerminal.getCode(), 0) > 1) { + addValidationError(validationErrors, "编码在本次导入中重复"); + } + if (count(Wrappers.lambdaQuery() + .eq(PortTerminal::getCode, portTerminal.getCode()) + .eq(PortTerminal::getIsDeleted, 0)) > 0L) { + addValidationError(validationErrors, "该编码已存在"); + } + } + if (Func.isEmpty(portTerminal.getName())) { + addValidationError(validationErrors, "港口/码头名称不能为空"); + } + validateImportLength(portTerminal.getName(), NAME_MAX_LENGTH, "港口/码头名称不能超过100字", validationErrors); + validateImportLength(portTerminal.getCountry(), REGION_MAX_LENGTH, "国家不能超过50字", validationErrors); + validateImportLength(portTerminal.getCity(), REGION_MAX_LENGTH, "城市不能超过50字", validationErrors); + validateImportLength(portTerminal.getDistrictName(), REGION_MAX_LENGTH, "区县不能超过50字", validationErrors); + validateImportLength(portTerminal.getRegionCode(), REGION_CODE_MAX_LENGTH, "行政区划编码不能超过32字", validationErrors); + validateImportLength(portTerminal.getDetailAddress(), DETAIL_ADDRESS_MAX_LENGTH, "详细地址不能超过255字", validationErrors); + validateImportLength(portTerminal.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200个字", validationErrors); + if (Func.isEmpty(portTerminal.getLongitude())) { + addValidationError(validationErrors, "经度不能为空"); + } else if (!validRange(portTerminal.getLongitude(), MIN_LONGITUDE, MAX_LONGITUDE)) { + addValidationError(validationErrors, "经度范围为 -180 到 180"); + } + if (Func.isEmpty(portTerminal.getLatitude())) { + addValidationError(validationErrors, "纬度不能为空"); + } else if (!validRange(portTerminal.getLatitude(), MIN_LATITUDE, MAX_LATITUDE)) { + addValidationError(validationErrors, "纬度范围为 -90 到 90"); + } + if (CATEGORY_PORT.equals(portTerminal.getCategory())) { + validateImportPortRegion(portTerminal, validationErrors); + } + if (CATEGORY_TERMINAL.equals(portTerminal.getCategory())) { + validateImportParentPort(portTerminal, validationErrors); + } + return validationErrors; + } + + private void validateImportPortRegion(PortTerminal portTerminal, List validationErrors) { + if (Func.isEmpty(portTerminal.getCountry())) { + addValidationError(validationErrors, "国家不能为空"); + } + if (Func.isEmpty(portTerminal.getCity())) { + addValidationError(validationErrors, "城市不能为空"); + } + if (Func.isEmpty(portTerminal.getDistrictCode()) && Func.isEmpty(portTerminal.getDistrictName())) { + addValidationError(validationErrors, "区县不能为空"); + return; + } + try { + fillRegion(portTerminal); + } catch (ServiceException exception) { + addValidationError(validationErrors, exception.getMessage()); + } + } + + private void validateImportParentPort(PortTerminal portTerminal, List validationErrors) { + if (Func.isEmpty(portTerminal.getParentCode())) { + addValidationError(validationErrors, "上级港口编码不能为空"); + return; + } + PortTerminal parentPort = getOne(Wrappers.lambdaQuery() + .eq(PortTerminal::getCode, portTerminal.getParentCode()) + .eq(PortTerminal::getCategory, CATEGORY_PORT) + .eq(PortTerminal::getIsDeleted, 0), false); + if (Func.isEmpty(parentPort)) { + addValidationError(validationErrors, "上级港口编码对应的港口不存在"); + } else if (Func.isNotEmpty(portTerminal.getParentName()) && !Objects.equals(portTerminal.getParentName(), parentPort.getName())) { + addValidationError(validationErrors, "上级港口与上级港口编码不匹配"); + } + if (Func.isNotEmpty(portTerminal.getCode()) && !portTerminal.getCode().startsWith(portTerminal.getParentCode() + "-")) { + addValidationError(validationErrors, "码头编码必须以上级港口编码开头"); + } + } + + private void validateImportLength(String value, int maxLength, String message, List validationErrors) { + if (Func.isNotEmpty(value) && value.length() > maxLength) { + addValidationError(validationErrors, message); + } + } + + private void addValidationError(List validationErrors, String message) { + if (Func.isNotEmpty(message) && !validationErrors.contains(message)) { + validationErrors.add(message); + } + } + @Override public List exportPortTerminal(Wrapper queryWrapper) { List portTerminalList = list(queryWrapper); diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/RailwayStationServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/RailwayStationServiceImpl.java index 590113a..0b73d06 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/RailwayStationServiceImpl.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/RailwayStationServiceImpl.java @@ -43,12 +43,15 @@ import org.springblade.system.service.IRailwayStationService; import org.springblade.system.service.IRegionService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; @@ -127,26 +130,196 @@ public class RailwayStationServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List railwayStationList = new ArrayList<>(); + Map tmisCodeCountMap = buildImportValueCountMap(data.stream() + .map(excel -> trimToEmpty(excel.getTmisCode())) + .toList()); + Map telegraphCodeCountMap = buildImportValueCountMap(data.stream() + .map(excel -> trimToEmpty(excel.getTelegraphCode()).toUpperCase(Locale.ROOT)) + .toList()); for (int index = 0; index < data.size(); index++) { RailwayStationExcel excel = data.get(index); + RailwayStation railwayStation = Objects.requireNonNull(BeanUtil.copyProperties(excel, RailwayStation.class)); + List validationErrors = new ArrayList<>(); + railwayStation.setLongitude(parseImportCoordinate(excel.getLongitude(), "经度", validationErrors)); + railwayStation.setLatitude(parseImportCoordinate(excel.getLatitude(), "纬度", validationErrors)); + railwayStation.setDataSource(SOURCE_BATCH); + railwayStation.setStatus(STATUS_ENABLED); + normalizeImportRailwayStation(railwayStation); + validationErrors.addAll(validateImportRailwayStation(railwayStation, tmisCodeCountMap, telegraphCodeCountMap)); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(formatImportErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } try { - RailwayStation railwayStation = Objects.requireNonNull(BeanUtil.copyProperties(excel, RailwayStation.class)); - railwayStation.setLongitude(parseCoordinate(excel.getLongitude(), "经度")); - railwayStation.setLatitude(parseCoordinate(excel.getLatitude(), "纬度")); - railwayStation.setDataSource(SOURCE_BATCH); - railwayStation.setStatus(STATUS_ENABLED); prepare(railwayStation, SOURCE_BATCH); validate(railwayStation); - save(railwayStation); + railwayStationList.add(railwayStation); } catch (Exception exception) { String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; - excel.setErrorMessage("第" + (index + 2) + "行:" + message); + excel.setErrorMessage(formatImportErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (RailwayStation railwayStation : railwayStationList) { + if (!save(railwayStation)) { + throw new ServiceException("铁路车站保存失败"); + } + } return errorList; } + private Map buildImportValueCountMap(List values) { + Map valueCountMap = new HashMap<>(); + for (String value : values) { + if (Func.isNotEmpty(value)) { + valueCountMap.merge(value, 1, Integer::sum); + } + } + return valueCountMap; + } + + private void normalizeImportRailwayStation(RailwayStation railwayStation) { + railwayStation.setTmisCode(trimToEmpty(railwayStation.getTmisCode())); + railwayStation.setCode(CODE_PREFIX + railwayStation.getTmisCode()); + railwayStation.setTelegraphCode(trimToEmpty(railwayStation.getTelegraphCode()).toUpperCase(Locale.ROOT)); + railwayStation.setName(trimToEmpty(railwayStation.getName())); + railwayStation.setProvinceCode(trimToNull(railwayStation.getProvinceCode())); + railwayStation.setProvinceName(trimToNull(railwayStation.getProvinceName())); + railwayStation.setCityCode(trimToNull(railwayStation.getCityCode())); + railwayStation.setCityName(trimToNull(railwayStation.getCityName())); + railwayStation.setDistrictCode(trimToNull(railwayStation.getDistrictCode())); + railwayStation.setDistrictName(trimToNull(railwayStation.getDistrictName())); + railwayStation.setRegionCode(trimToNull(railwayStation.getRegionCode())); + if (Func.isEmpty(railwayStation.getDistrictCode()) && Func.isNotEmpty(railwayStation.getRegionCode())) { + railwayStation.setDistrictCode(railwayStation.getRegionCode()); + } + railwayStation.setDetailAddress(trimToNull(railwayStation.getDetailAddress())); + railwayStation.setRemark(trimToNull(railwayStation.getRemark())); + } + + private BigDecimal parseImportCoordinate(String value, String name, List validationErrors) { + String trimValue = trimToEmpty(value); + if (trimValue.isEmpty()) { + return null; + } + try { + return new BigDecimal(trimValue); + } catch (NumberFormatException exception) { + addValidationError(validationErrors, name + "范围不正确"); + return null; + } + } + + private List validateImportRailwayStation(RailwayStation railwayStation, + Map tmisCodeCountMap, Map telegraphCodeCountMap) { + List validationErrors = new ArrayList<>(); + if (Func.isEmpty(railwayStation.getTmisCode())) { + addValidationError(validationErrors, "TMIS国标编码不能为空"); + } else { + if (!TMIS_CODE_PATTERN.matcher(railwayStation.getTmisCode()).matches()) { + addValidationError(validationErrors, "TMIS国标编码为5位数字"); + } + if (tmisCodeCountMap.getOrDefault(railwayStation.getTmisCode(), 0) > 1) { + addValidationError(validationErrors, "TMIS国标编码在本次导入中重复"); + } + validateImportUnique(RailwayStation::getTmisCode, railwayStation.getTmisCode(), "该TMIS国标编码已存在", validationErrors); + validateImportUnique(RailwayStation::getCode, railwayStation.getCode(), "该编码已存在", validationErrors); + } + if (Func.isEmpty(railwayStation.getTelegraphCode())) { + addValidationError(validationErrors, "电报码不能为空"); + } else { + if (!TELEGRAPH_CODE_PATTERN.matcher(railwayStation.getTelegraphCode()).matches()) { + addValidationError(validationErrors, "电报码为3位大写字母"); + } + if (telegraphCodeCountMap.getOrDefault(railwayStation.getTelegraphCode(), 0) > 1) { + addValidationError(validationErrors, "电报码在本次导入中重复"); + } + validateImportUnique(RailwayStation::getTelegraphCode, railwayStation.getTelegraphCode(), "电报码已存在", validationErrors); + } + if (Func.isEmpty(railwayStation.getName())) { + addValidationError(validationErrors, "车站名称不能为空"); + } + validateImportLength(railwayStation.getCode(), CODE_MAX_LENGTH, "编码不能超过20字", validationErrors); + validateImportLength(railwayStation.getName(), NAME_MAX_LENGTH, "车站名称不能超过50字", validationErrors); + validateImportLength(railwayStation.getProvinceName(), REGION_NAME_MAX_LENGTH, "所属省份不能超过128字", validationErrors); + validateImportLength(railwayStation.getCityName(), REGION_NAME_MAX_LENGTH, "所属城市不能超过128字", validationErrors); + validateImportLength(railwayStation.getDistrictName(), REGION_NAME_MAX_LENGTH, "所属区县不能超过128字", validationErrors); + validateImportLength(railwayStation.getRegionCode(), REGION_CODE_MAX_LENGTH, "行政区划编号不能超过32字", validationErrors); + validateImportLength(railwayStation.getDetailAddress(), DETAIL_ADDRESS_MAX_LENGTH, "详细地址不能超过255字", validationErrors); + validateImportLength(railwayStation.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字", validationErrors); + validateImportCoordinate(railwayStation.getLongitude(), MIN_LONGITUDE, MAX_LONGITUDE, "经度", validationErrors); + validateImportCoordinate(railwayStation.getLatitude(), MIN_LATITUDE, MAX_LATITUDE, "纬度", validationErrors); + validateImportRailwayRegion(railwayStation, validationErrors); + return validationErrors; + } + + private void validateImportRailwayRegion(RailwayStation railwayStation, List validationErrors) { + boolean provinceMissing = Func.isEmpty(railwayStation.getProvinceCode()) && Func.isEmpty(railwayStation.getProvinceName()); + boolean cityMissing = Func.isEmpty(railwayStation.getCityCode()) && Func.isEmpty(railwayStation.getCityName()); + boolean districtMissing = Func.isEmpty(railwayStation.getDistrictCode()) && Func.isEmpty(railwayStation.getDistrictName()); + if (provinceMissing) { + addValidationError(validationErrors, "所属省份不能为空"); + } + if (cityMissing) { + addValidationError(validationErrors, "所属城市不能为空"); + } + if (districtMissing) { + addValidationError(validationErrors, "所属区县不能为空"); + } + if (provinceMissing || cityMissing || districtMissing) { + return; + } + try { + fillRegion(railwayStation); + } catch (ServiceException exception) { + addValidationError(validationErrors, exception.getMessage()); + } + } + + private void validateImportCoordinate(BigDecimal value, BigDecimal min, BigDecimal max, String name, List validationErrors) { + if (Func.isNotEmpty(value) && !validRange(value, min, max)) { + addValidationError(validationErrors, name + "范围不正确"); + } + } + + private void validateImportUnique(com.baomidou.mybatisplus.core.toolkit.support.SFunction column, + String value, String message, List validationErrors) { + if (count(Wrappers.lambdaQuery() + .eq(column, value) + .eq(RailwayStation::getIsDeleted, 0)) > 0L) { + addValidationError(validationErrors, message); + } + } + + private void validateImportLength(String value, int maxLength, String message, List validationErrors) { + if (Func.isNotEmpty(value) && value.length() > maxLength) { + addValidationError(validationErrors, message); + } + } + + private void addValidationError(List validationErrors, String message) { + if (Func.isNotEmpty(message) && !validationErrors.contains(message)) { + validationErrors.add(message); + } + } + + private String formatImportErrorMessage(int rowNumber, List validationErrors) { + StringBuilder errorMessage = new StringBuilder("第").append(rowNumber).append("行:"); + for (int index = 0; index < validationErrors.size(); index++) { + if (index > 0) { + errorMessage.append(System.lineSeparator()); + } + errorMessage.append(index + 1).append(". ").append(validationErrors.get(index)); + } + return errorMessage.toString(); + } + @Override public List exportRailwayStation(Wrapper queryWrapper) { List railwayStationList = list(queryWrapper); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AccidentRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AccidentRecordServiceImpl.java index b56a3e2..d98fd41 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AccidentRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AccidentRecordServiceImpl.java @@ -45,6 +45,7 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Set; /** * 事故记录 服务实现类 @@ -62,6 +63,8 @@ public class AccidentRecordServiceImpl extends BaseServiceImpl ACCIDENT_NATURES = Set.of("重大事故", "一般事故", "轻微事故", "其他"); + private static final Set ACCIDENT_RESPONSIBILITIES = Set.of("全部责任", "主要责任", "同等责任", "次要责任", "无责任"); @Override public IPage selectAccidentRecordPage(IPage page, AccidentRecordVO accidentRecord) { @@ -86,19 +89,64 @@ public class AccidentRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List accidentRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { AccidentRecordExcel excel = data.get(index); try { AccidentRecord accidentRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, AccidentRecord.class)); - submit(accidentRecord); + prepare(accidentRecord); + List validationErrors = validateImportAccidentRecord(accidentRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + validateVehicleTypeImmutable(accidentRecord); + accidentRecordList.add(accidentRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (AccidentRecord accidentRecord : accidentRecordList) { + if (!save(accidentRecord)) { + throw new ServiceException("事故记录保存失败"); + } + } return errorList; } + private List validateImportAccidentRecord(AccidentRecord accidentRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(accidentRecord.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(accidentRecord.getVehicleType()) && !VEHICLE.equals(accidentRecord.getVehicleType()) && !SHIP.equals(accidentRecord.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(accidentRecord.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(accidentRecord.getAccidentDate()), "事故发生日期不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(accidentRecord.getAccidentNature()), "事故性质不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(accidentRecord.getAccidentNature()) && !ACCIDENT_NATURES.contains(accidentRecord.getAccidentNature()), "事故性质不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(accidentRecord.getAccidentResponsibility()), "事故责任不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(accidentRecord.getAccidentResponsibility()) && !ACCIDENT_RESPONSIBILITIES.contains(accidentRecord.getAccidentResponsibility()), "事故责任不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, accidentRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, accidentRecord.getAccidentLocation(), LOCATION_MAX_LENGTH, "事故发生地点不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, accidentRecord.getAccidentReasonDamage(), REASON_DAMAGE_MAX_LENGTH, "事故原因及损坏情况不能超过500字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, accidentRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, accidentRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + addImportMoneyErrors(validationErrors, accidentRecord.getDirectEconomicLoss(), "直接经济损失"); + addImportMoneyErrors(validationErrors, accidentRecord.getInsuranceClaimAmount(), "保险理赔金额"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(accidentRecord.getInsuranceClaimAmount()) && Func.isNotEmpty(accidentRecord.getDirectEconomicLoss()) && accidentRecord.getInsuranceClaimAmount().compareTo(accidentRecord.getDirectEconomicLoss()) > 0, "保险理赔金额不能超过直接经济损失金额"); + return validationErrors; + } + + private void addImportMoneyErrors(List validationErrors, BigDecimal value, String fieldName) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.stripTrailingZeros().scale() > MONEY_SCALE, fieldName + "最多保留2位小数"); + } + @Override public List exportAccidentRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(accidentRecord -> { @@ -137,9 +185,15 @@ public class AccidentRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List annualInspectionRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { AnnualInspectionRecordExcel excel = data.get(index); try { AnnualInspectionRecord annualInspectionRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, AnnualInspectionRecord.class)); - submit(annualInspectionRecord); + prepare(annualInspectionRecord); + List validationErrors = validateImportAnnualInspectionRecord(annualInspectionRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + validateVehicleTypeImmutable(annualInspectionRecord); + annualInspectionRecordList.add(annualInspectionRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (AnnualInspectionRecord annualInspectionRecord : annualInspectionRecordList) { + if (!save(annualInspectionRecord)) { + throw new ServiceException("年检记录保存失败"); + } + } return errorList; } + private List validateImportAnnualInspectionRecord(AnnualInspectionRecord annualInspectionRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(annualInspectionRecord.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(annualInspectionRecord.getVehicleType()) && !VEHICLE.equals(annualInspectionRecord.getVehicleType()) && !SHIP.equals(annualInspectionRecord.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(annualInspectionRecord.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, VEHICLE.equals(annualInspectionRecord.getVehicleType()) && Func.isEmpty(annualInspectionRecord.getVehicleTechnicalLevel()), "车辆技术等级不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, SHIP.equals(annualInspectionRecord.getVehicleType()) && Func.isEmpty(annualInspectionRecord.getShipInspectionType()), "船舶检验类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(annualInspectionRecord.getValidUntilDate()), "有效期截止日不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(annualInspectionRecord.getValidUntilDate()) && Func.isNotEmpty(annualInspectionRecord.getInspectionAssessmentDate()) && !annualInspectionRecord.getValidUntilDate().isAfter(annualInspectionRecord.getInspectionAssessmentDate()), "有效期截止日应大于检测评定日期"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(annualInspectionRecord.getFee()), "费用不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, annualInspectionRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, annualInspectionRecord.getPassengerTypeLevel(), PASSENGER_TYPE_LEVEL_MAX_LENGTH, "客车类型及等级不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, annualInspectionRecord.getInspectionUnit(), INSPECTION_UNIT_MAX_LENGTH, "检测评定单位不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, annualInspectionRecord.getAssessmentUnit(), ASSESSMENT_UNIT_MAX_LENGTH, "评定(复核)单位不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, annualInspectionRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, annualInspectionRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + addImportMoneyErrors(validationErrors, annualInspectionRecord.getFee(), "费用"); + return validationErrors; + } + + private void addImportMoneyErrors(List validationErrors, BigDecimal value, String fieldName) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.stripTrailingZeros().scale() > MONEY_SCALE, fieldName + "最多保留2位小数"); + } + @Override public List exportAnnualInspectionRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(annualInspectionRecord -> { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EquipmentLedgerServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EquipmentLedgerServiceImpl.java index a657eac..5a89a52 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EquipmentLedgerServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EquipmentLedgerServiceImpl.java @@ -19,8 +19,10 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; /** * 设备台账服务实现 @@ -68,19 +70,63 @@ public class EquipmentLedgerServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List equipmentLedgerList = new ArrayList<>(); + Set importEquipmentCodes = new HashSet<>(); for (int index = 0; index < data.size(); index++) { EquipmentLedgerExcel excel = data.get(index); try { EquipmentLedger equipmentLedger = Objects.requireNonNull(BeanUtil.copyProperties(excel, EquipmentLedger.class)); - submit(equipmentLedger); + prepare(equipmentLedger); + if (equipmentLedger.getId() == null && Func.isEmpty(equipmentLedger.getEquipmentCode())) { + equipmentLedger.setEquipmentCode(nextEquipmentCode(importEquipmentCodes)); + } + List validationErrors = validateImportEquipmentLedger(equipmentLedger); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, + !importEquipmentCodes.add(equipmentLedger.getEquipmentCode()), "设备编号在本次导入中重复"); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + validateEquipmentCodeImmutable(equipmentLedger); + equipmentLedgerList.add(equipmentLedger); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (EquipmentLedger equipmentLedger : equipmentLedgerList) { + if (!save(equipmentLedger)) { + throw new ServiceException("设备台账保存失败"); + } + } return errorList; } + private List validateImportEquipmentLedger(EquipmentLedger equipmentLedger) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, !VEHICLE.equals(equipmentLedger.getVehicleType()) && !SHIP.equals(equipmentLedger.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(equipmentLedger.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(equipmentLedger.getEquipmentCode()), "设备编号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(equipmentLedger.getEquipmentName()), "设备名称不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, equipmentLedger.getOnlineStatus() != 0 && equipmentLedger.getOnlineStatus() != 1, "是否在线不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getEquipmentCode(), EQUIPMENT_CODE_MAX_LENGTH, "设备编号格式不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getEquipmentName(), EQUIPMENT_NAME_MAX_LENGTH, "设备名称不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getEquipmentBrand(), EQUIPMENT_BRAND_MAX_LENGTH, "设备品牌不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getEquipmentType(), EQUIPMENT_TYPE_MAX_LENGTH, "设备类型不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getSpecificationModel(), SPECIFICATION_MODEL_MAX_LENGTH, "规格型号不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getOriginalEquipmentNo(), ORIGINAL_EQUIPMENT_NO_MAX_LENGTH, "原厂设备号不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, equipmentLedger.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + return validationErrors; + } + @Override public List exportEquipmentLedger(Wrapper queryWrapper) { return list(queryWrapper).stream() @@ -90,10 +136,14 @@ public class EquipmentLedgerServiceImpl extends BaseServiceImpl importEquipmentCodes) { String prefix = "EQ" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); for (int sequence = 1; sequence <= 99; sequence++) { String code = prefix + String.format("%02d", sequence); - if (!exists(new LambdaQueryWrapper().eq(EquipmentLedger::getEquipmentCode, code))) { + if (!importEquipmentCodes.contains(code) && !exists(new LambdaQueryWrapper().eq(EquipmentLedger::getEquipmentCode, code))) { return code; } } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EtcRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EtcRecordServiceImpl.java index 8dbf6a3..053907a 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EtcRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EtcRecordServiceImpl.java @@ -64,20 +64,60 @@ public class EtcRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List etcRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { EtcRecordExcel excel = data.get(index); try { EtcRecord etcRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, EtcRecord.class)); etcRecord.setDataSource("批量导入"); - submit(etcRecord); + prepare(etcRecord); + List validationErrors = validateImportEtcRecord(etcRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + etcRecordList.add(etcRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (EtcRecord etcRecord : etcRecordList) { + if (!save(etcRecord)) { + throw new ServiceException("ETC记录保存失败"); + } + } return errorList; } + private List validateImportEtcRecord(EtcRecord etcRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(etcRecord.getVehicleNo()), "车牌号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(etcRecord.getEtcCardNo()), "ETC卡号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(etcRecord.getExitTime()), "出口时间不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(etcRecord.getTransactionAmount()), "交易金额不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(etcRecord.getEntryTime()) && Func.isNotEmpty(etcRecord.getExitTime()) && !etcRecord.getExitTime().isAfter(etcRecord.getEntryTime()), "出口时间应大于入口时间"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, etcRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, etcRecord.getEtcCardNo(), ETC_CARD_NO_MAX_LENGTH, "ETC卡号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, etcRecord.getEntryStation(), STATION_MAX_LENGTH, "入口站不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, etcRecord.getExitStation(), STATION_MAX_LENGTH, "出口站不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, etcRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, etcRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + addImportMoneyErrors(validationErrors, etcRecord.getTransactionAmount(), "交易金额"); + return validationErrors; + } + + private void addImportMoneyErrors(List validationErrors, BigDecimal value, String fieldName) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.stripTrailingZeros().scale() > MONEY_SCALE, fieldName + "最多保留" + MONEY_SCALE + "位小数"); + } + @Override public List exportEtcRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(etcRecord -> { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InsuranceRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InsuranceRecordServiceImpl.java index a6efd6e..c821f7e 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InsuranceRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InsuranceRecordServiceImpl.java @@ -57,6 +57,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.util.Collection; import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -81,6 +82,7 @@ public class InsuranceRecordServiceImpl extends BaseServiceImpl INSURANCE_TYPES = Set.of("交强险", "商业险", "承运人责任险", "货运险", "船舶险"); private static final Set SUPPORT_FILE_TYPES = Set.of("jpg", "jpeg", "png", "bmp"); private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4})[-/.年](\\d{1,2})[-/.月](\\d{1,2})日?"); @@ -110,19 +112,71 @@ public class InsuranceRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List insuranceRecordList = new ArrayList<>(); + Set importPolicyKeys = new HashSet<>(); for (int index = 0; index < data.size(); index++) { InsuranceRecordExcel excel = data.get(index); try { InsuranceRecord insuranceRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, InsuranceRecord.class)); - submit(insuranceRecord); + prepare(insuranceRecord); + List validationErrors = validateImportInsuranceRecord(insuranceRecord); + if (Func.isNotEmpty(insuranceRecord.getVehicleType()) && Func.isNotEmpty(insuranceRecord.getInsuranceType()) && Func.isNotEmpty(insuranceRecord.getPolicyNo())) { + String policyKey = insuranceRecord.getVehicleType() + "\u0000" + insuranceRecord.getInsuranceType() + "\u0000" + insuranceRecord.getPolicyNo(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, !importPolicyKeys.add(policyKey), "同一车船类型和保险类型下保单号在本次导入中重复"); + } + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + checkUniquePolicyNo(insuranceRecord); + insuranceRecordList.add(insuranceRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (InsuranceRecord insuranceRecord : insuranceRecordList) { + if (!save(insuranceRecord)) { + throw new ServiceException("保险记录保存失败"); + } + } return errorList; } + private List validateImportInsuranceRecord(InsuranceRecord insuranceRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(insuranceRecord.getVehicleType()) && !"车辆".equals(insuranceRecord.getVehicleType()) && !"船舶".equals(insuranceRecord.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getInsuranceType()), "保险类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(insuranceRecord.getInsuranceType()) && !INSURANCE_TYPES.contains(insuranceRecord.getInsuranceType()), "保险类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getPolicyNo()), "保单号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getStartDate()), "开始日期不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getEndDate()), "结束日期不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(insuranceRecord.getStartDate()) && Func.isNotEmpty(insuranceRecord.getEndDate()) && insuranceRecord.getEndDate().isBefore(insuranceRecord.getStartDate()), "结束日期不能早于开始日期"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getPremium()), "保费不能为空"); + addImportNonNegativeError(validationErrors, insuranceRecord.getInsuredAmount(), "保额不能小于0"); + addImportNonNegativeError(validationErrors, insuranceRecord.getPremium(), "保费不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, insuranceRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, insuranceRecord.getInsuranceType(), INSURANCE_TYPE_MAX_LENGTH, "保险类型不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, insuranceRecord.getPolicyNo(), POLICY_NO_MAX_LENGTH, "保单号不能超过80字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, insuranceRecord.getInvoiceNo(), INVOICE_NO_MAX_LENGTH, "发票号不能超过80字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, insuranceRecord.getOcrTemplate(), OCR_TEMPLATE_MAX_LENGTH, "OCR识别模板不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, insuranceRecord.getPolicyFile(), POLICY_FILE_MAX_LENGTH, "保单附件不能超过1000字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, insuranceRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + return validationErrors; + } + + private void addImportNonNegativeError(List validationErrors, BigDecimal value, String message) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, message); + } + @Override public List exportInsuranceRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(insuranceRecord -> { @@ -288,6 +342,9 @@ public class InsuranceRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List maintenancePlanList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { MaintenancePlanExcel excel = data.get(index); try { MaintenancePlan maintenancePlan = Objects.requireNonNull(BeanUtil.copyProperties(excel, MaintenancePlan.class)); - submit(maintenancePlan); + prepare(maintenancePlan); + List validationErrors = validateImportMaintenancePlan(maintenancePlan); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + maintenancePlanList.add(maintenancePlan); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (MaintenancePlan maintenancePlan : maintenancePlanList) { + if (!save(maintenancePlan)) { + throw new ServiceException("保养计划保存失败"); + } + } return errorList; } + private List validateImportMaintenancePlan(MaintenancePlan maintenancePlan) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(maintenancePlan.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenancePlan.getVehicleType()) && !"车辆".equals(maintenancePlan.getVehicleType()) && !"船舶".equals(maintenancePlan.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(maintenancePlan.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenancePlan.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenancePlan.getMaintainer(), MAINTAINER_MAX_LENGTH, "保养人不能超过20字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenancePlan.getMaintenanceItem(), MAINTENANCE_ITEM_MAX_LENGTH, "保养项目不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenancePlan.getAddress(), ADDRESS_MAX_LENGTH, "地址不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenancePlan.getRemark(), REMARK_MAX_LENGTH, "备注不能超过500字"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(maintenancePlan.getMaintenanceTime()), "保养时间不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(maintenancePlan.getCost()), "费用不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenancePlan.getCost()) && maintenancePlan.getCost().compareTo(BigDecimal.ZERO) < 0, "费用不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenancePlan.getMileage()) && maintenancePlan.getMileage().compareTo(BigDecimal.ZERO) < 0, "里程/航程数不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenancePlan.getNextMaintenanceMileage()) && maintenancePlan.getNextMaintenanceMileage().compareTo(BigDecimal.ZERO) < 0, "下次保养里程/航程不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenancePlan.getNextMaintenanceTime()) && Func.isNotEmpty(maintenancePlan.getMaintenanceTime()) && maintenancePlan.getNextMaintenanceTime().isBefore(maintenancePlan.getMaintenanceTime()), "下次保养时间不能早于保养时间"); + return validationErrors; + } + @Override public List exportMaintenancePlan(Wrapper queryWrapper) { return list(queryWrapper).stream().map(maintenancePlan -> { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MaintenanceRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MaintenanceRecordServiceImpl.java index fef55c3..5ae4cb6 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MaintenanceRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MaintenanceRecordServiceImpl.java @@ -84,21 +84,58 @@ public class MaintenanceRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List maintenanceRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { MaintenanceRecordExcel excel = data.get(index); try { MaintenanceRecord maintenanceRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, MaintenanceRecord.class)); maintenanceRecord.setCreateTime(null); maintenanceRecord.setUpdateTime(null); - submit(maintenanceRecord); + prepare(maintenanceRecord); + List validationErrors = validateImportMaintenanceRecord(maintenanceRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + maintenanceRecordList.add(maintenanceRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (MaintenanceRecord maintenanceRecord : maintenanceRecordList) { + if (!save(maintenanceRecord)) { + throw new ServiceException("车辆维修记录保存失败"); + } + } return errorList; } + private List validateImportMaintenanceRecord(MaintenanceRecord maintenanceRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(maintenanceRecord.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenanceRecord.getVehicleType()) && !"车辆".equals(maintenanceRecord.getVehicleType()) && !"船舶".equals(maintenanceRecord.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(maintenanceRecord.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenanceRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenanceRecord.getMaintainer(), MAINTAINER_MAX_LENGTH, "维修人不能超过20字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenanceRecord.getLocation(), LOCATION_MAX_LENGTH, "维修位置不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenanceRecord.getReplacedPart(), REPLACED_PART_MAX_LENGTH, "更换零件不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenanceRecord.getAddress(), ADDRESS_MAX_LENGTH, "地址不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, maintenanceRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过500字"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(maintenanceRecord.getMaintenanceTime()), "维修时间不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(maintenanceRecord.getCost()), "费用不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenanceRecord.getCost()) && maintenanceRecord.getCost().compareTo(BigDecimal.ZERO) < 0, "费用不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenanceRecord.getMileage()) && maintenanceRecord.getMileage().compareTo(BigDecimal.ZERO) < 0, "里程/航程数不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(maintenanceRecord.getFactoryTime()) && Func.isNotEmpty(maintenanceRecord.getMaintenanceTime()) && maintenanceRecord.getFactoryTime().isBefore(maintenanceRecord.getMaintenanceTime()), "出厂时间不能早于维修时间"); + return validationErrors; + } + @Override public List exportMaintenanceRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(maintenanceRecord -> { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MileageRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MileageRecordServiceImpl.java index 6aa427b..1660e23 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MileageRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MileageRecordServiceImpl.java @@ -84,19 +84,62 @@ public class MileageRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List mileageRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { MileageRecordExcel excel = data.get(index); try { MileageRecord mileageRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, MileageRecord.class)); - submit(mileageRecord); + prepare(mileageRecord); + List validationErrors = validateImportMileageRecord(mileageRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + validateVehicleNoImmutable(mileageRecord); + mileageRecordList.add(mileageRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (MileageRecord mileageRecord : mileageRecordList) { + if (!save(mileageRecord)) { + throw new ServiceException("里程记录保存失败"); + } + } return errorList; } + private List validateImportMileageRecord(MileageRecord mileageRecord) { + List validationErrors = new ArrayList<>(); + boolean isShip = VEHICLE_TYPE_SHIP.equals(mileageRecord.getVehicleType()); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, !VEHICLE_TYPE_VEHICLE.equals(mileageRecord.getVehicleType()) && !isShip, "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(mileageRecord.getVehicleNo()), isShip ? "船号不能为空" : "车牌号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, mileageRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, isShip ? "船号不能超过30字" : "车牌号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, mileageRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, mileageRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + addImportMileageErrors(validationErrors, mileageRecord.getPreviousMonthMileage(), isShip ? "上月统计航程数" : "上月统计里程数"); + addImportMileageErrors(validationErrors, mileageRecord.getCurrentMonthMileage(), isShip ? "本月统计航程数" : "本月统计里程数"); + addImportMileageErrors(validationErrors, mileageRecord.getMonthlyMileage(), isShip ? "本月航行航程数" : "本月行驶里程数"); + addImportMileageErrors(validationErrors, mileageRecord.getTotalMileage(), isShip ? "累计航程数" : "累计行驶里程数"); + if (mileageRecord.getPreviousMonthMileage() != null && mileageRecord.getCurrentMonthMileage() != null && mileageRecord.getMonthlyMileage() != null) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, mileageRecord.getCurrentMonthMileage().subtract(mileageRecord.getPreviousMonthMileage()).compareTo(mileageRecord.getMonthlyMileage()) != 0, isShip ? "本月航行航程数应等于本月统计航程数减去上月统计航程数" : "本月行驶里程数应等于本月统计里程数减去上月统计里程数"); + } + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, mileageRecord.getTotalMileage() != null && mileageRecord.getCurrentMonthMileage() != null && mileageRecord.getTotalMileage().compareTo(mileageRecord.getCurrentMonthMileage()) < 0, isShip ? "累计航程数应大于等于本月统计航程数" : "累计行驶里程数应大于等于本月统计里程数"); + return validationErrors; + } + + private void addImportMileageErrors(List validationErrors, BigDecimal value, String fieldName) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.stripTrailingZeros().scale() > MILEAGE_SCALE, fieldName + "最多保留2位小数"); + } + @Override public List exportMileageRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(mileageRecord -> { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OilElectricRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OilElectricRecordServiceImpl.java index eab4a7e..4a3ebb9 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OilElectricRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OilElectricRecordServiceImpl.java @@ -73,20 +73,66 @@ public class OilElectricRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List oilElectricRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { OilElectricRecordExcel excel = data.get(index); try { OilElectricRecord oilElectricRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, OilElectricRecord.class)); oilElectricRecord.setDataSource(defaultDataSource(oilElectricRecord.getDataSource())); - submit(oilElectricRecord); + prepare(oilElectricRecord); + List validationErrors = validateImportOilElectricRecord(oilElectricRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + oilElectricRecordList.add(oilElectricRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (OilElectricRecord oilElectricRecord : oilElectricRecordList) { + if (!save(oilElectricRecord)) { + throw new ServiceException("油电记录保存失败"); + } + } return errorList; } + private List validateImportOilElectricRecord(OilElectricRecord oilElectricRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(oilElectricRecord.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(oilElectricRecord.getVehicleType()) && !VEHICLE.equals(oilElectricRecord.getVehicleType()) && !SHIP.equals(oilElectricRecord.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(oilElectricRecord.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(oilElectricRecord.getTransactionTime()), "交易时间不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(oilElectricRecord.getFeeType()), "费用类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(oilElectricRecord.getFeeType()) && !FEE_TYPES.contains(oilElectricRecord.getFeeType()), "费用类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(oilElectricRecord.getTransactionAmount()), "交易金额不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, oilElectricRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, oilElectricRecord.getCardNo(), CARD_NO_MAX_LENGTH, "卡号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, oilElectricRecord.getCardHolder(), CARD_HOLDER_MAX_LENGTH, "持卡人不能超过20字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, oilElectricRecord.getOilProduct(), OIL_PRODUCT_MAX_LENGTH, "油品不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, oilElectricRecord.getStation(), STATION_MAX_LENGTH, "站点不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, oilElectricRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, oilElectricRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + addImportNumberErrors(validationErrors, oilElectricRecord.getTransactionAmount(), "交易金额", MONEY_SCALE); + addImportNumberErrors(validationErrors, oilElectricRecord.getUnitPrice(), "单价", MONEY_SCALE); + addImportNumberErrors(validationErrors, oilElectricRecord.getBalance(), "余额", MONEY_SCALE); + addImportNumberErrors(validationErrors, oilElectricRecord.getQuantity(), "数量", QUANTITY_SCALE); + return validationErrors; + } + + private void addImportNumberErrors(List validationErrors, BigDecimal value, String fieldName, int scale) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.stripTrailingZeros().scale() > scale, fieldName + "最多保留" + scale + "位小数"); + } + @Override public List exportOilElectricRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(oilElectricRecord -> { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OtherExpenseRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OtherExpenseRecordServiceImpl.java index dd803fc..ab1f838 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OtherExpenseRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OtherExpenseRecordServiceImpl.java @@ -67,20 +67,59 @@ public class OtherExpenseRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List otherExpenseRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { OtherExpenseRecordExcel excel = data.get(index); try { OtherExpenseRecord otherExpenseRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, OtherExpenseRecord.class)); otherExpenseRecord.setDataSource("批量导入"); - submit(otherExpenseRecord); + prepare(otherExpenseRecord); + List validationErrors = validateImportOtherExpenseRecord(otherExpenseRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + otherExpenseRecordList.add(otherExpenseRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (OtherExpenseRecord otherExpenseRecord : otherExpenseRecordList) { + if (!save(otherExpenseRecord)) { + throw new ServiceException("其他费用记录保存失败"); + } + } return errorList; } + private List validateImportOtherExpenseRecord(OtherExpenseRecord otherExpenseRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getExpenseDate()), "费用日期不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getExpenseType()), "费用类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(otherExpenseRecord.getExpenseType()) && !EXPENSE_TYPES.contains(otherExpenseRecord.getExpenseType()), "费用类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(otherExpenseRecord.getVehicleType()) && !VEHICLE.equals(otherExpenseRecord.getVehicleType()) && !SHIP.equals(otherExpenseRecord.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getAmount()), "金额不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, otherExpenseRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, otherExpenseRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, otherExpenseRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + addImportMoneyErrors(validationErrors, otherExpenseRecord.getAmount(), "金额"); + return validationErrors; + } + + private void addImportMoneyErrors(List validationErrors, BigDecimal value, String fieldName) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.stripTrailingZeros().scale() > MONEY_SCALE, fieldName + "最多保留" + MONEY_SCALE + "位小数"); + } + @Override public List exportOtherExpenseRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(otherExpenseRecord -> { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TireReplacementRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TireReplacementRecordServiceImpl.java index 2f73ef1..1bee220 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TireReplacementRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TireReplacementRecordServiceImpl.java @@ -84,19 +84,54 @@ public class TireReplacementRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List tireReplacementRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { TireReplacementRecordExcel excel = data.get(index); try { TireReplacementRecord tireReplacementRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, TireReplacementRecord.class)); - submit(tireReplacementRecord); + prepare(tireReplacementRecord); + List validationErrors = validateImportTireReplacementRecord(tireReplacementRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + tireReplacementRecordList.add(tireReplacementRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (TireReplacementRecord tireReplacementRecord : tireReplacementRecordList) { + if (!save(tireReplacementRecord)) { + throw new ServiceException("轮胎更换记录保存失败"); + } + } return errorList; } + private List validateImportTireReplacementRecord(TireReplacementRecord tireReplacementRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(tireReplacementRecord.getVehicleNo()), "车牌号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(tireReplacementRecord.getReplacementTime()), "换胎时间不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(tireReplacementRecord.getReplacementCost()), "换胎费用不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, tireReplacementRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, tireReplacementRecord.getHandler(), HANDLER_MAX_LENGTH, "处理人不能超过20字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, tireReplacementRecord.getTireBrand(), TIRE_BRAND_MAX_LENGTH, "轮胎品牌不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, tireReplacementRecord.getReplacementDescription(), DESCRIPTION_MAX_LENGTH, "换胎说明不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, tireReplacementRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过500字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, tireReplacementRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(tireReplacementRecord.getTireQuantity()) && tireReplacementRecord.getTireQuantity() <= 0, "更换轮胎数量必须大于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(tireReplacementRecord.getReplacementCost()) && tireReplacementRecord.getReplacementCost().compareTo(BigDecimal.ZERO) < 0, "换胎费用不能小于0"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(tireReplacementRecord.getReplacementCost()) && tireReplacementRecord.getReplacementCost().stripTrailingZeros().scale() > 2, "换胎费用最多保留2位小数"); + return validationErrors; + } + @Override public List exportTireReplacementRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(tireReplacementRecord -> { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportChangeRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportChangeRecordServiceImpl.java index 184fb6b..22737b0 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportChangeRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TransportChangeRecordServiceImpl.java @@ -84,19 +84,51 @@ public class TransportChangeRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List transportChangeRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { TransportChangeRecordExcel excel = data.get(index); try { TransportChangeRecord transportChangeRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, TransportChangeRecord.class)); - submit(transportChangeRecord); + prepare(transportChangeRecord); + List validationErrors = validateImportTransportChangeRecord(transportChangeRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + transportChangeRecordList.add(transportChangeRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (TransportChangeRecord transportChangeRecord : transportChangeRecordList) { + if (!save(transportChangeRecord)) { + throw new ServiceException("变更记录保存失败"); + } + } return errorList; } + private List validateImportTransportChangeRecord(TransportChangeRecord transportChangeRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(transportChangeRecord.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(transportChangeRecord.getVehicleType()) && !VEHICLE.equals(transportChangeRecord.getVehicleType()) && !SHIP.equals(transportChangeRecord.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(transportChangeRecord.getChangeItem()), "变更事项不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(transportChangeRecord.getChangeItem()) && !CHANGE_ITEMS.contains(transportChangeRecord.getChangeItem()), "变更事项不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(transportChangeRecord.getChangeContent()), "变更内容不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, transportChangeRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, transportChangeRecord.getChangeContent(), CHANGE_CONTENT_MAX_LENGTH, "变更内容不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, transportChangeRecord.getRemark(), REMARK_MAX_LENGTH, "备注不能超过200字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, transportChangeRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + return validationErrors; + } + @Override public List exportTransportChangeRecord(Wrapper queryWrapper) { return list(queryWrapper).stream() diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ViolationRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ViolationRecordServiceImpl.java index ed9dfe9..75200fa 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ViolationRecordServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ViolationRecordServiceImpl.java @@ -91,6 +91,7 @@ public class ViolationRecordServiceImpl extends BaseServiceImpl errorList = new ArrayList<>(); + List violationRecordList = new ArrayList<>(); for (int index = 0; index < data.size(); index++) { ViolationRecordImportExcel excel = data.get(index); try { @@ -100,15 +101,65 @@ public class ViolationRecordServiceImpl extends BaseServiceImpl validationErrors = validateImportViolationRecord(violationRecord); + if (Func.isNotEmpty(validationErrors)) { + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, validationErrors)); + errorList.add(excel); + continue; + } + validateVehicleTypeImmutable(violationRecord); + violationRecordList.add(violationRecord); } catch (Exception exception) { - excel.setErrorMessage("第" + (index + 2) + "行:" + exception.getMessage()); + String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败"; + excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(index + 2, List.of(message))); errorList.add(excel); } } + if (Func.isNotEmpty(errorList)) { + org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return errorList; + } + for (ViolationRecord violationRecord : violationRecordList) { + if (!save(violationRecord)) { + throw new ServiceException("违章记录保存失败"); + } + } return errorList; } + private List validateImportViolationRecord(ViolationRecord violationRecord) { + List validationErrors = new ArrayList<>(); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getVehicleType()), "车船类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getVehicleType()) && !"车辆".equals(violationRecord.getVehicleType()) && !"船舶".equals(violationRecord.getVehicleType()), "车船类型不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getVehicleNo()), "车牌号/船号不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getDriverName()), "驾驶人/船长不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, "车辆".equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationType()), "类型不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, "船舶".equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationItem()), "事项不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getViolationTime()), "时间不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getViolationTime()) && violationRecord.getViolationTime().isAfter(LocalDateTime.now()), "时间不能超过当前时间"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getLocation()), "地址不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getProcessStatus()), "状态不能为空"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getProcessStatus()) && !PROCESSED.equals(violationRecord.getProcessStatus()) && !UNPROCESSED.equals(violationRecord.getProcessStatus()), "状态值不正确"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getProcessDescription()), "过程描述不能为空"); + addImportNonNegativeError(validationErrors, violationRecord.getFineAmount(), "被罚金额"); + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getDeductPoints()) && (violationRecord.getDeductPoints() < 0 || violationRecord.getDeductPoints() > MAX_DEDUCT_POINTS), "被扣分数范围为0-15分"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getDriverName(), DRIVER_NAME_MAX_LENGTH, "驾驶人/船长不能超过20字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getViolationType(), TYPE_MAX_LENGTH, "类型不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getViolationItem(), ITEM_MAX_LENGTH, "事项不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getLocation(), LOCATION_MAX_LENGTH, "地址不能超过100字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getPenaltyUnit(), PENALTY_UNIT_MAX_LENGTH, "被罚单位不能超过50字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getProcessDescription(), DESCRIPTION_MAX_LENGTH, "过程描述不能超过500字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getProcessResult(), RESULT_MAX_LENGTH, "处理结果不能超过500字"); + org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件不能超过1000字"); + return validationErrors; + } + + private void addImportNonNegativeError(List validationErrors, BigDecimal value, String fieldName) { + org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0"); + } + @Override public List exportViolationRecord(Wrapper queryWrapper) { return list(queryWrapper).stream().map(violationRecord -> {