xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/vehicleConvoy/BaseVehicleUserDto.java
@@ -6,7 +6,7 @@ @Data public class BaseVehicleUserDto { /** * 状态码 * 状态码 0成功 */ private Integer code; /** xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java
@@ -26,6 +26,7 @@ import com.xiaopeng.map.mapper.XpPointMapper; import com.xiaopeng.map.mapper.XpRegionMapper; import com.xiaopeng.map.service.XpElectronicFenceService; import com.xiaopeng.map.utils.GDMapGeocodingUtil; import com.xiaopeng.map.utils.PolygonOverlapService; import lombok.extern.slf4j.Slf4j; import net.sourceforge.pinyin4j.PinyinHelper; @@ -66,6 +67,8 @@ private XpPointMapper xpPointMapper; @Autowired private XpRegionMapper xpRegionMapper; @Autowired private GDMapGeocodingUtil gdMapGeocodingUtil; @Override public PageInfo<XpElectronicFence> pageList(ElectronicPageListQuery query) { @@ -155,6 +158,16 @@ } } } //根据经纬度获取当前城市code XpElectronicFenceArea xpElectronicFenceArea = dto.getElectronicFenceAreas().get(0); String[] split = xpElectronicFenceArea.getFencePoints().split(",")[0].split("_"); Map<String, String> geocode = gdMapGeocodingUtil.geocode(split[0], split[1]); if(null == geocode){ return R.fail("经纬度转换城市code失败"); } String cityCode = geocode.get("cityCode"); dto.setCityCode(cityCode); xpElectronicFence.setCityCode(dto.getCityCode()); // 生成围栏id 规则:城市首字母-类型简写-4位自增流水号(如 SZ-OP-001),支持复制;数据停用或删除后,流水号不回收 XpRegion xpRegion = xpRegionMapper.selectOne(new LambdaQueryWrapper<XpRegion>() @@ -363,6 +376,15 @@ } } } //根据经纬度获取当前城市code XpElectronicFenceArea electronicFenceArea = dto.getElectronicFenceAreas().get(0); String[] split = electronicFenceArea.getFencePoints().split(",")[0].split("_"); Map<String, String> geocode = gdMapGeocodingUtil.geocode(split[0], split[1]); if(null == geocode){ return R.fail("经纬度转换城市code失败"); } String cityCode = geocode.get("cityCode"); dto.setCityCode(cityCode); xpElectronicFence.setCityCode(dto.getCityCode()); this.updateById(xpElectronicFence); xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/GDMapGeocodingUtil.java
@@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; /** * 高德地图的地理编码工具类 @@ -121,4 +122,37 @@ return jsonObject.getString("data"); } /** * 根据经纬度获取行政区域信息 * @param lon * @param lan * @return * @throws Exception */ public Map<String, String> geocode(String lon, String lan) { String url = "https://restapi.amap.com/v3/geocode/regeo?key=" + key + "&location=" + lon + "," + lan; String forObject = HttpUtils.sendGet(url); JSONObject jsonObject = JSON.parseObject(forObject); Map<String, String> map = new HashMap<>(); if(jsonObject.getString("status").equals("1")){ JSONObject regeocode = jsonObject.getJSONObject("regeocode"); JSONObject addressComponent = regeocode.getJSONObject("addressComponent"); String address = regeocode.getString("formatted_address"); map.put("address", address); String code = addressComponent.getString("adcode"); String province = addressComponent.getString("province"); String city = addressComponent.getString("city"); String district = addressComponent.getString("district"); map.put("province", province); map.put("provinceCode", code.substring(0, 2) + "0000"); map.put("city", city); map.put("cityCode", code.substring(0, 4) + "00"); map.put("district", district); map.put("districtCode", code); } return map; } } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpElectronicFenceServiceImpl.java
@@ -28,6 +28,7 @@ import com.xiaopeng.operation.mapper.XpPointMapper; import com.xiaopeng.operation.mapper.XpRegionMapper; import com.xiaopeng.operation.service.IXpElectronicFenceService; import com.xiaopeng.operation.utils.GDMapGeocodingUtil; import com.xiaopeng.operation.utils.PolygonOverlapService; import lombok.extern.slf4j.Slf4j; import net.sourceforge.pinyin4j.PinyinHelper; @@ -67,6 +68,8 @@ private XpPointMapper xpPointMapper; @Autowired private XpRegionMapper xpRegionMapper; @Autowired private GDMapGeocodingUtil gdMapGeocodingUtil; @Override public PageInfo<XpElectronicFence> pageList(ElectronicPageListQuery query) { @@ -157,6 +160,15 @@ } } } //根据经纬度获取当前城市code XpElectronicFenceArea xpElectronicFenceArea = dto.getElectronicFenceAreas().get(0); String[] split = xpElectronicFenceArea.getFencePoints().split(",")[0].split("_"); Map<String, String> geocode = gdMapGeocodingUtil.geocode(split[0], split[1]); if(null == geocode){ return R.fail("经纬度转换城市code失败"); } String cityCode = geocode.get("cityCode"); dto.setCityCode(cityCode); xpElectronicFence.setCityCode(dto.getCityCode()); // 生成围栏id 规则:城市首字母-类型简写-4位自增流水号(如 SZ-OP-001),支持复制;数据停用或删除后,流水号不回收 XpRegion xpRegion = xpRegionMapper.selectOne(new LambdaQueryWrapper<XpRegion>() @@ -366,8 +378,16 @@ } } } //根据经纬度获取当前城市code XpElectronicFenceArea electronicFenceArea = dto.getElectronicFenceAreas().get(0); String[] split = electronicFenceArea.getFencePoints().split(",")[0].split("_"); Map<String, String> geocode = gdMapGeocodingUtil.geocode(split[0], split[1]); if(null == geocode){ return R.fail("经纬度转换城市code失败"); } String cityCode = geocode.get("cityCode"); dto.setCityCode(cityCode); xpElectronicFence.setCityCode(dto.getCityCode()); this.updateById(xpElectronicFence); // 删除旧的区域数据,然后保存新的区域数据 xpElectronicFenceAreaMapper.delete(new LambdaQueryWrapper<XpElectronicFenceArea>() xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/GDMapGeocodingUtil.java
New file @@ -0,0 +1,56 @@ package com.xiaopeng.operation.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.xiaopeng.common.core.utils.HttpUtils; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; /** * 高德地图的地理编码工具类 */ @Component @Lazy public class GDMapGeocodingUtil { private String key = "66ae577f63898dae3016d599fda57221"; /** * 根据经纬度获取行政区域信息 * @param lon * @param lan * @return * @throws Exception */ public Map<String, String> geocode(String lon, String lan) { String url = "https://restapi.amap.com/v3/geocode/regeo?key=" + key + "&location=" + lon + "," + lan; String forObject = HttpUtils.sendGet(url); JSONObject jsonObject = JSON.parseObject(forObject); Map<String, String> map = new HashMap<>(); if(jsonObject.getString("status").equals("1")){ JSONObject regeocode = jsonObject.getJSONObject("regeocode"); JSONObject addressComponent = regeocode.getJSONObject("addressComponent"); String address = regeocode.getString("formatted_address"); map.put("address", address); String code = addressComponent.getString("adcode"); String province = addressComponent.getString("province"); String city = addressComponent.getString("city"); String district = addressComponent.getString("district"); map.put("province", province); map.put("provinceCode", code.substring(0, 2) + "0000"); map.put("city", city); map.put("cityCode", code.substring(0, 4) + "00"); map.put("district", district); map.put("districtCode", code); } return map; } } xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -49,6 +49,7 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; @@ -348,21 +349,21 @@ Locale locale = LocaleContextHolder.getLocale(); if (dto.getAnnualInspectionDate() != null && dto.getAnnualInspectionDate().isBefore(now)) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { expiredItems.add("年检到期时间"); } else { expiredItems.add("Annual inspection expiration date"); } } if (dto.getInsuranceEndTime() != null && dto.getInsuranceEndTime().isBefore(now)) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { expiredItems.add("保险到期时间"); } else { expiredItems.add("Insurance expiration date"); } } if (dto.getQualificationExpireTime() != null && dto.getQualificationExpireTime().isBefore(now)) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { expiredItems.add("运营资质到期时间"); } else { expiredItems.add("Operation qualification expiration date"); @@ -371,7 +372,7 @@ if (!expiredItems.isEmpty()) { String detail; if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { detail = String.join("、", expiredItems); } else { detail = String.join("; ", expiredItems); @@ -393,7 +394,7 @@ || StringUtils.isBlank(vehicle.getInsurancePhone()) || vehicle.getInsuranceEndTime() == null || StringUtils.isBlank(vehicle.getPolicyInformation())) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { missingItems.add("保险信息"); } else { missingItems.add("Insurance information"); @@ -403,7 +404,7 @@ // 校验年检信息 if (vehicle.getAnnualInspectionDate() == null || StringUtils.isBlank(vehicle.getInspectionAttachments())) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { missingItems.add("年检信息"); } else { missingItems.add("Annual inspection information"); @@ -412,7 +413,7 @@ // 校验运营区域 if (vehicle.getElectronicId() == null) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { missingItems.add("运营区域"); } else { missingItems.add("Operation area"); @@ -422,7 +423,7 @@ // 校验运营资质 if (StringUtils.isBlank(vehicle.getOperationQualification()) || vehicle.getQualificationExpireTime() == null) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { missingItems.add("运营资质"); } else { missingItems.add("Operation qualification"); @@ -431,7 +432,7 @@ if (!missingItems.isEmpty()) { String detail; if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { detail = String.join("、", missingItems); } else { detail = String.join("; ", missingItems); @@ -455,6 +456,32 @@ && vehicle.getQualificationExpireTime() != null; } /** * 检查车辆是否有任意一项证件过期(精确到日期) * - 精确度:yyyy-MM-dd(只比较日期部分) * - 到期日期等于今天不算过期(使用 isBefore) * @param vehicle 车辆信息 * @param today 今天日期 */ private boolean isAnyDateExpired(XpVehicle vehicle, LocalDate today) { // 年检到期时间检查:已过期 if (vehicle.getAnnualInspectionDate() != null && vehicle.getAnnualInspectionDate().toLocalDate().isBefore(today)) { return true; } // 保险到期时间检查:已过期 if (vehicle.getInsuranceEndTime() != null && vehicle.getInsuranceEndTime().toLocalDate().isBefore(today)) { return true; } // 运营资质到期时间检查:已过期 if (vehicle.getQualificationExpireTime() != null && vehicle.getQualificationExpireTime().toLocalDate().isBefore(today)) { return true; } return false; } @Override @Transactional(rollbackFor = Exception.class) public void batchOperation(String idStr) { @@ -464,7 +491,7 @@ List<String> ids = Arrays.asList(idStr.split(",")); // 查询车辆完整信息 List<XpVehicle> vehicles = this.listByIds(ids); LocalDateTime now = LocalDateTime.now(); LocalDate now = LocalDate.now(); List<String> errorMessages = new ArrayList<>(); for (XpVehicle vehicle : vehicles) { @@ -473,38 +500,38 @@ // 校验状态为待运营 if (!Integer.valueOf(2).equals(vehicle.getStatus())) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { reasons.add("状态非待运营"); } else { reasons.add("Status is not 'Pending Operation'"); } } // 校验年检到期时间 if (vehicle.getAnnualInspectionDate() == null || vehicle.getAnnualInspectionDate().isBefore(now)) { if (locale.equals(Locale.CHINESE)) { if (vehicle.getAnnualInspectionDate() == null || vehicle.getAnnualInspectionDate().toLocalDate().isBefore(now)) { if ("zh".equals(locale.getLanguage())) { reasons.add("年检已过期"); } else { reasons.add("Annual inspection has expired"); } } // 校验保险到期时间 if (vehicle.getInsuranceEndTime() == null || vehicle.getInsuranceEndTime().isBefore(now)) { if (locale.equals(Locale.CHINESE)) { if (vehicle.getInsuranceEndTime() == null || vehicle.getInsuranceEndTime().toLocalDate().isBefore(now)) { if ("zh".equals(locale.getLanguage())) { reasons.add("保险已过期"); } else { reasons.add("Insurance has expired"); } } // 校验运营资质到期时间 if (vehicle.getQualificationExpireTime() == null || vehicle.getQualificationExpireTime().isBefore(now)) { if (locale.equals(Locale.CHINESE)) { if (vehicle.getQualificationExpireTime() == null || vehicle.getQualificationExpireTime().toLocalDate().isBefore(now)) { if ("zh".equals(locale.getLanguage())) { reasons.add("运营资质已过期"); } else { reasons.add("Operation qualification has expired"); } } if (!reasons.isEmpty()) { if (locale.equals(Locale.CHINESE)) { if ("zh".equals(locale.getLanguage())) { errorMessages.add("车辆[" + vehicle.getPlateNumber() + "]:" + String.join("、", reasons)); } else { errorMessages.add("Vehicles [" + vehicle.getPlateNumber() + "]: " + String.join("; ", reasons)); @@ -558,6 +585,32 @@ public PageInfo<XpVehicle> vehiclePageList(VehiclePageQuery query) { PageInfo<XpVehicle> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); List<XpVehicle> list = this.baseMapper.vehiclePageList(pageInfo, query); if (CollUtil.isNotEmpty(list)) { LocalDate today = LocalDate.now(); List<Long> expiredVehicleIds = new ArrayList<>(); for (XpVehicle vehicle : list) { // 检查是否有任意一项过期(精确到 yyyy-MM-dd) boolean isExpired = isAnyDateExpired(vehicle, today); if (isExpired && !Integer.valueOf(3).equals(vehicle.getStatus())) { // 记录需要更新状态的车辆ID expiredVehicleIds.add(vehicle.getId()); // 同时更新返回结果中的状态 vehicle.setStatus(3); } } // 批量更新过期车辆状态到数据库 if (CollUtil.isNotEmpty(expiredVehicleIds)) { LambdaUpdateWrapper<XpVehicle> updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.in(XpVehicle::getId, expiredVehicleIds) .set(XpVehicle::getStatus, 3); this.update(updateWrapper); } } pageInfo.setRecords(list); return pageInfo; }