From f3a8ace95bb141026b694b70df4d41bf284c6a7d Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期三, 11 三月 2026 21:50:11 +0800
Subject: [PATCH] Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi

---
 xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java |  195 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 194 insertions(+), 1 deletions(-)

diff --git a/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java b/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
index dbe612a..5229a8b 100644
--- a/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
+++ b/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -5,6 +5,7 @@
 import cn.afterturn.easypoi.excel.entity.ExportParams;
 import cn.afterturn.easypoi.excel.entity.ImportParams;
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.lang.Validator;
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -69,8 +70,13 @@
 import java.net.URLEncoder;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Pattern;
 
 /**
  * <p>
@@ -85,6 +91,9 @@
 @Api(tags = "车辆管理")
 @RequiredArgsConstructor(onConstructor_ = @Lazy)
 public class XpVehicleController {
+
+    private static final Pattern VEHICLE_CODE_PATTERN = Pattern.compile("^[A-Za-z0-9_]{1,5}$");
+    private static final Pattern VEHICLE_VIN_PATTERN = Pattern.compile("^[A-Z0-9]{17}$");
 
     private final IXpVehicleService xpVehicleService;
     private final IXpFleetVehicleService vehicleService;
@@ -267,7 +276,7 @@
      */
     @ApiOperation(value = "导入", tags = {"管理后台-车辆管理-在库车辆管理"})
     @PostMapping("/api/v1/vehicle/importExcel")
-    public R<?> importExcel(@RequestPart("file") MultipartFile file) {
+    public R<?> importExcel(@RequestParam("file") MultipartFile file) {
         ImportParams params = new ImportParams();
         params.setHeadRows(1);
         InputStream inputStream = null;
@@ -294,6 +303,7 @@
             throw new ServiceException("导入数据为空!", I18nKeyConstant.VEHICLE_IMPORT_DATA_EMPTY);
         }
         validateImportRequiredFields(importList, params.getHeadRows());
+        validateImportBusinessFields(importList, params.getHeadRows());
         uploadVehiclePicture(importList);
         xpVehicleService.importVehicles(importList);
         return R.ok();
@@ -326,6 +336,189 @@
         }
     }
 
+    private void validateImportBusinessFields(List<XpVehicleImportExcel> importList, int headRows) {
+        List<String> errors = new ArrayList<>();
+        Locale locale = LocaleContextHolder.getLocale();
+
+        for (int index = 0; index < importList.size(); index++) {
+            XpVehicleImportExcel row = importList.get(index);
+            int excelRowNumber = index + headRows + 1;
+
+            String vehicleCode = trimToNull(row.getVehicleCode());
+            String vehicleVin = normalizeVin(row.getVehicleVin());
+            String plateNumber = trimToNull(row.getPlateNumber());
+            String vehicleColor = trimToNull(row.getVehicleColor());
+
+            row.setVehicleCode(vehicleCode);
+            row.setVehicleVin(vehicleVin);
+            row.setPlateNumber(plateNumber);
+            row.setVehicleColor(vehicleColor);
+
+            if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleCode) && !VEHICLE_CODE_PATTERN.matcher(vehicleCode).matches()) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_INVALID,
+                        new Object[]{excelRowNumber, vehicleCode},
+                        I18nKeyConstant.VEHICLE_IMPORT_CODE_INVALID,
+                        locale));
+            }
+            if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleVin) && !VEHICLE_VIN_PATTERN.matcher(vehicleVin).matches()) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_INVALID,
+                        new Object[]{excelRowNumber, vehicleVin},
+                        I18nKeyConstant.VEHICLE_IMPORT_VIN_INVALID,
+                        locale));
+            }
+            if (org.apache.commons.lang3.StringUtils.isNotBlank(plateNumber) && !Validator.isPlateNumber(plateNumber)) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_INVALID,
+                        new Object[]{excelRowNumber, plateNumber},
+                        I18nKeyConstant.VEHICLE_IMPORT_PLATE_INVALID,
+                        locale));
+            }
+            if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleColor) && vehicleColor.length() > 2) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_COLOR_INVALID,
+                        new Object[]{excelRowNumber, vehicleColor},
+                        I18nKeyConstant.VEHICLE_IMPORT_COLOR_INVALID,
+                        locale));
+            }
+        }
+
+        Set<String> duplicatedCodes = findDuplicated(importList.stream()
+                .map(XpVehicleImportExcel::getVehicleCode)
+                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                .collect(java.util.stream.Collectors.toList()));
+        Set<String> duplicatedVins = findDuplicated(importList.stream()
+                .map(XpVehicleImportExcel::getVehicleVin)
+                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                .collect(java.util.stream.Collectors.toList()));
+        Set<String> duplicatedPlates = findDuplicated(importList.stream()
+                .map(XpVehicleImportExcel::getPlateNumber)
+                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                .collect(java.util.stream.Collectors.toList()));
+
+        for (int index = 0; index < importList.size(); index++) {
+            XpVehicleImportExcel row = importList.get(index);
+            int excelRowNumber = index + headRows + 1;
+            if (duplicatedCodes.contains(row.getVehicleCode())) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_DUPLICATE,
+                        new Object[]{excelRowNumber, row.getVehicleCode()},
+                        I18nKeyConstant.VEHICLE_IMPORT_CODE_DUPLICATE,
+                        locale));
+            }
+            if (duplicatedVins.contains(row.getVehicleVin())) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_DUPLICATE,
+                        new Object[]{excelRowNumber, row.getVehicleVin()},
+                        I18nKeyConstant.VEHICLE_IMPORT_VIN_DUPLICATE,
+                        locale));
+            }
+            if (duplicatedPlates.contains(row.getPlateNumber())) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_DUPLICATE,
+                        new Object[]{excelRowNumber, row.getPlateNumber()},
+                        I18nKeyConstant.VEHICLE_IMPORT_PLATE_DUPLICATE,
+                        locale));
+            }
+        }
+
+        Set<String> codeSet = importList.stream()
+                .map(XpVehicleImportExcel::getVehicleCode)
+                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                .collect(java.util.stream.Collectors.toSet());
+        Set<String> vinSet = importList.stream()
+                .map(XpVehicleImportExcel::getVehicleVin)
+                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                .collect(java.util.stream.Collectors.toSet());
+        Set<String> plateSet = importList.stream()
+                .map(XpVehicleImportExcel::getPlateNumber)
+                .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                .collect(java.util.stream.Collectors.toSet());
+
+        Set<String> existsCodes = Collections.emptySet();
+        if (!codeSet.isEmpty()) {
+            existsCodes = xpVehicleService.lambdaQuery()
+                    .select(XpVehicle::getVehicleCode)
+                    .in(XpVehicle::getVehicleCode, codeSet)
+                    .list()
+                    .stream()
+                    .map(XpVehicle::getVehicleCode)
+                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                    .collect(java.util.stream.Collectors.toSet());
+        }
+        Set<String> existsVins = Collections.emptySet();
+        if (!vinSet.isEmpty()) {
+            existsVins = xpVehicleService.lambdaQuery()
+                    .select(XpVehicle::getVehicleVin)
+                    .in(XpVehicle::getVehicleVin, vinSet)
+                    .list()
+                    .stream()
+                    .map(XpVehicle::getVehicleVin)
+                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                    .collect(java.util.stream.Collectors.toSet());
+        }
+        Set<String> existsPlates = Collections.emptySet();
+        if (!plateSet.isEmpty()) {
+            existsPlates = xpVehicleService.lambdaQuery()
+                    .select(XpVehicle::getPlateNumber)
+                    .in(XpVehicle::getPlateNumber, plateSet)
+                    .list()
+                    .stream()
+                    .map(XpVehicle::getPlateNumber)
+                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
+                    .collect(java.util.stream.Collectors.toSet());
+        }
+
+        for (int index = 0; index < importList.size(); index++) {
+            XpVehicleImportExcel row = importList.get(index);
+            int excelRowNumber = index + headRows + 1;
+            if (existsCodes.contains(row.getVehicleCode())) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_EXISTS,
+                        new Object[]{excelRowNumber, row.getVehicleCode()},
+                        I18nKeyConstant.VEHICLE_IMPORT_CODE_EXISTS,
+                        locale));
+            }
+            if (existsVins.contains(row.getVehicleVin())) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_EXISTS,
+                        new Object[]{excelRowNumber, row.getVehicleVin()},
+                        I18nKeyConstant.VEHICLE_IMPORT_VIN_EXISTS,
+                        locale));
+            }
+            if (existsPlates.contains(row.getPlateNumber())) {
+                errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_EXISTS,
+                        new Object[]{excelRowNumber, row.getPlateNumber()},
+                        I18nKeyConstant.VEHICLE_IMPORT_PLATE_EXISTS,
+                        locale));
+            }
+        }
+
+        if (!errors.isEmpty()) {
+            throw new ServiceException("导入校验失败!", I18nKeyConstant.VEHICLE_IMPORT_VALIDATE_FAIL,
+                    new Object[]{String.join("\n", errors)});
+        }
+    }
+
+    private static String normalizeVin(String vin) {
+        String trimmed = trimToNull(vin);
+        return trimmed == null ? null : trimmed.toUpperCase(Locale.ROOT);
+    }
+
+    private static String trimToNull(String value) {
+        if (value == null) {
+            return null;
+        }
+        String trimmed = value.trim();
+        return trimmed.isEmpty() ? null : trimmed;
+    }
+
+    private static Set<String> findDuplicated(List<String> values) {
+        if (values == null || values.isEmpty()) {
+            return Collections.emptySet();
+        }
+        Set<String> seen = new HashSet<>();
+        Set<String> duplicated = new HashSet<>();
+        for (String value : values) {
+            if (!seen.add(value)) {
+                duplicated.add(value);
+            }
+        }
+        return duplicated;
+    }
+
     private void uploadVehiclePicture(List<XpVehicleImportExcel> importList) {
         for (XpVehicleImportExcel xpVehicleImportExcel : importList) {
             xpVehicleImportExcel.setVehiclePictures(getOssUrl(xpVehicleImportExcel.getVehiclePictures()));

--
Gitblit v1.7.1