| | |
| | | import com.xiaopeng.api.model.vehicleConvoy.*; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.operation.ElectronicFenceDetailVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandEnum; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleStateVo;import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandEnum; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandParamVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandVo; |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | |
| | | import com.xiaopeng.common.core.utils.GeodesyUtil; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.evi.oss.service.AliOssService; |
| | | import com.xiaopeng.vehicleConvoy.constant.I18nKeyConstant; |
| | | import com.xiaopeng.vehicleConvoy.mapper.XpFleetMapper; |
| | | import com.xiaopeng.vehicleConvoy.mapper.XpFleetOperationsMapper; |
| | |
| | | import com.xiaopeng.vehicleConvoy.util.VehicleControlUtil; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType; |
| | | import org.apache.shardingsphere.transaction.core.TransactionType; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.i18n.LocaleContextHolder; |
| | | import org.springframework.data.geo.Point; |
| | |
| | | private RedisService redisService; |
| | | @Autowired |
| | | private MongoTemplate mongoTemplate; |
| | | @Autowired |
| | | private AliOssService aliOssService; |
| | | @Autowired |
| | | private RedisTemplate redisTemplate; |
| | | @Autowired |
| | |
| | | return pageInfo; |
| | | } |
| | | |
| | | List<Long> vehicleIds = xpFleetVehicles.stream().map(XpFleetVehicle::getVehicleId).collect(Collectors.toList()); |
| | | List<Long> vehicleIds = xpFleetVehicles.stream().map(XpFleetVehicle::getVehicleId).distinct().collect(Collectors.toList()); |
| | | query.setVehicleIds(vehicleIds); |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | for (XpVehicleVO xpVehicleVO : list) { |
| | | // List<Point> positionList = redisTemplate.opsForGeo().position("vehiclePosition:" + xpVehicleVO.getVehicleVin(), xpVehicleVO.getVehicleVin()); |
| | | // if (!CollectionUtils.isEmpty(positionList)) { |
| | | // Point geoJsonPoint = positionList.get(0); |
| | | // // 获取经纬度 |
| | | // xpVehicleVO.setLongitude(geoJsonPoint.getX()); |
| | | // xpVehicleVO.setLatitude(geoJsonPoint.getY()); |
| | | // } |
| | | // 查询车辆的续航里程 |
| | | VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicleVO.getVehicleVin())), VehiclePosition.class); |
| | | if (Objects.nonNull(vehiclePosition)) { |
| | |
| | | } else { |
| | | xpVehicleVO.setMileageRange(0F); |
| | | xpVehicleVO.setCurrentElectricity(0); |
| | | xpVehicleVO.setLongitude(104.056302); |
| | | xpVehicleVO.setLatitude(30.586688); |
| | | } |
| | | if (org.springframework.util.StringUtils.hasLength(xpVehicleVO.getVehiclePictures())) { |
| | | JSONObject jsonObject = JSONObject.parseObject(xpVehicleVO.getVehiclePictures()); |
| | | if(jsonObject!=null){ |
| | | String downloadUrl = null; |
| | | try { |
| | | // 1 |
| | | downloadUrl= aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | jsonObject.put("url", downloadUrl); |
| | | xpVehicleVO.setVehiclePictures(jsonObject.toJSONString()); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | if (Objects.isNull(xpVehicle)) { |
| | | throw new ServiceException("未查询到有效车辆信息", I18nKeyConstant.VEHICLE_NOT_EXISTS); |
| | | } |
| | | // 判断距离是否在范围之内 4米 |
| | | // List<Point> positionList = redisTemplate.opsForGeo().position("vehiclePosition:" + xpVehicle.getVehicleVin(), xpVehicle.getVehicleVin()); |
| | | // 判断距离是否在范围之内 15米 |
| | | VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class); |
| | | if (Objects.nonNull(vehiclePosition)) { |
| | | GeoJsonPoint point = vehiclePosition.getPoint(); |
| | |
| | | Map<String, Double> distance = GeodesyUtil.getDistance(dto.getLongitude()+ "," + dto.getLatitude(), point.getX()+","+point.getY()); |
| | | if (null != distance) { |
| | | Double distance1 = distance.get("WGS84"); |
| | | if (distance1 > 4) { |
| | | throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG); |
| | | if (distance1 > 50) { |
| | | throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG); |
| | | } |
| | | }else { |
| | | throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG); |
| | | throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG); |
| | | } |
| | | }else { |
| | | throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG); |
| | | throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG); |
| | | } |
| | | } |
| | | // 车门解锁、后备箱解锁 |
| | |
| | | vehiclesCommandVo.setVin(xpVehicle.getVehicleVin()); |
| | | if ("door".equals(dto.getDoorType())) { |
| | | // 开启车门 判断是否为P档 |
| | | Integer gearLevel = redisService.getCacheObject(CacheConstants.GEAR_LEVEL + xpVehicle.getVehicleVin()); |
| | | Integer gearLevel = redisService.getCacheObject(CacheConstants.GEAR_LEVEL + xpVehicle.getXpuId()); |
| | | if (gearLevel == null || gearLevel != 4) { |
| | | throw new ServiceException("车辆非P档,无法开启车门", I18nKeyConstant.VEHICLE_NOT_P_GEAR); |
| | | } |
| | |
| | | // 开启后备箱 判断是否为P档 |
| | | Integer gearLevel = redisService.getCacheObject(CacheConstants.GEAR_LEVEL + xpVehicle.getXpuId()); |
| | | if (gearLevel == null || gearLevel != 4) { |
| | | throw new ServiceException("车辆非P档,无法开启后备箱", I18nKeyConstant.VEHICLE_NOT_P_GEAR); |
| | | throw new ServiceException("车辆非P档,无法操作后备箱", I18nKeyConstant.VEHICLE_NOT_P_GEAR); |
| | | } |
| | | vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_OPEN.getCommand()); |
| | | if(xpOrder.getOpenTrunk()==0){ |
| | | xpOrder.setOpenTrunk(1); |
| | | } |
| | | if(xpOrder.getOpenTrunk()==1){ |
| | | //查询后备箱开关状态 |
| | | VehicleTemperatureDto vehicleTemperatureDto = vehicleControlUtil.queryVehicleTemperature(String.valueOf(xpOrder.getAppUserId()), xpVehicle.getVehicleVin()); |
| | | VehicleStateVo trunkAjarCloseSt = vehicleTemperatureDto.getStateMap().get("trunkAjarCloseSt"); |
| | | //打开状态 |
| | | if(null != trunkAjarCloseSt && trunkAjarCloseSt.getValue().equals("1")){ |
| | | xpOrder.setOpenTrunk(2); |
| | | // 添加定时任务 |
| | | xpOrderClient.updateOrderStatus(xpOrder.getId(),7); |
| | | // 推送倒计时消息 消息推送 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId", xpOrder.getId().toString()); |
| | | content.put("isOpen", 1); |
| | | params.put("type", PushMessageTypeEnum.OPEN_TRUNK.getDesc()); |
| | | params.put("content", JSONObject.toJSONString(content)); |
| | | params.put("timestamp", new Date().getTime() + ""); |
| | | String message = JSONObject.toJSONString(params); |
| | | SendMessageDTO sendMessageDTO = new SendMessageDTO(); |
| | | sendMessageDTO.setMessage(message); |
| | | sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId())); |
| | | xpPushMessageClient.sendStatus(sendMessageDTO); |
| | | vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_CLOSE.getCommand()); |
| | | }else{ |
| | | //关闭状态 |
| | | xpOrder.setOpenTrunk(1); |
| | | vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_OPEN.getCommand()); |
| | | } |
| | | } |
| | | try { |
| | | // { |
| | | // "code": 0, |
| | | // "data": { |
| | | // "msgId": "1234556" |
| | | // }, |
| | | // "msg": "", |
| | | // "desc": "成功" |
| | | //} |
| | | String result = vehicleControlUtil.vehiclesCommand(vehiclesCommandVo, xpOrder.getAppUserId()); |
| | | log.info("车辆控制结果:{}", result); |
| | | xpOrderClient.updateOrder(xpOrder); |
| | | return 1; |
| | | if (!result.contains("msgId")) { |
| | | return 0; |
| | | }else { |
| | | xpOrderClient.updateOrder(xpOrder); |
| | | return 1; |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("车辆控制异常:{}", e.getMessage()); |
| | | return 0; |
| | |
| | | vehiclesCommandVo.setExtParam(vehiclesCommandParamVo); |
| | | try { |
| | | String result = vehicleControlUtil.vehiclesCommand(vehiclesCommandVo, xpOrder.getAppUserId()); |
| | | log.info("车辆控制结果:{}", result); |
| | | return 1; |
| | | log.info("车辆温度设置结果:{}", result); |
| | | if (!result.contains("msgId")) { |
| | | return 0; |
| | | }else { |
| | | return 1; |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("车辆控制异常:{}", e.getMessage()); |
| | | log.info("车辆温度设置异常:{}", e.getMessage()); |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void addVehicle(VehicleAddDTO dto) { |
| | | String normalizedVehicleCode = trimToNull(dto.getVehicleCode()); |
| | | String normalizedVin = normalizeVin(dto.getVehicleVin()); |
| | |
| | | xpVehicle.setVehicleType(1); |
| | | // 新增时状态为待完善 |
| | | xpVehicle.setStatus(1); |
| | | |
| | | // 设置入库时间 |
| | | xpVehicle.setWarehousingTime(LocalDateTime.now()); |
| | | //绑定XPUID |
| | | String vin = xpVehicle.getVehicleVin(); |
| | | String xpuid = xpuVinClient.getXpuIdByVin(vin).getData(); |
| | | R<String> xpuIdByVin = xpuVinClient.getXpuIdByVin(vin); |
| | | if(200 != xpuIdByVin.getCode()){ |
| | | throw new RuntimeException(xpuIdByVin.getMsg()); |
| | | } |
| | | String xpuid = xpuIdByVin.getData(); |
| | | xpVehicle.setXpuId(xpuid); |
| | | this.save(xpVehicle); |
| | | if (isInfoComplete(xpVehicle)) { |
| | | //如果信息完善则状态改为待运营 |
| | | xpVehicle.setStatus(2); |
| | | this.updateById(xpVehicle); |
| | | //保存年检记录 |
| | | XpVehicleAnnualRecord xpVehicleAnnualRecord = BeanUtil.copyProperties(dto, XpVehicleAnnualRecord.class, "id"); |
| | | xpVehicleAnnualRecord.setVehicleId(xpVehicle.getId()); |
| | | xpVehicleAnnualRecordService.save(xpVehicleAnnualRecord); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void editVehicle(VehicleEditDTO dto) { |
| | | XpVehicle existingVehicle = this.getById(dto.getId()); |
| | | String normalizedVehicleCode = trimToNull(dto.getVehicleCode()); |
| | | String normalizedVin = normalizeVin(dto.getVehicleVin()); |
| | | String normalizedPlateNumber = trimToNull(dto.getPlateNumber()); |
| | | String normalizedVehicleColor = trimToNull(dto.getVehicleColor()); |
| | | validateAndNormalizeIdentityFields(normalizedVehicleCode, normalizedVin, normalizedPlateNumber, normalizedVehicleColor, dto.getId()); |
| | | validateElectronicFenceExists(dto.getElectronicId()); |
| | | boolean electronicIdChanged = existingVehicle == null |
| | | || !Objects.equals(existingVehicle.getElectronicId(), dto.getElectronicId()); |
| | | if (electronicIdChanged) { |
| | | validateElectronicFenceExists(dto.getElectronicId()); |
| | | } |
| | | |
| | | dto.setVehicleCode(normalizedVehicleCode); |
| | | dto.setVehicleVin(normalizedVin); |
| | |
| | | // DTO转实体 |
| | | XpVehicle xpVehicle = new XpVehicle(); |
| | | BeanUtil.copyProperties(dto, xpVehicle); |
| | | //绑定XPUID |
| | | String vin = xpVehicle.getVehicleVin(); |
| | | String xpuid = xpuVinClient.getXpuIdByVin(vin).getData(); |
| | | xpVehicle.setXpuId(xpuid); |
| | | boolean vinChanged = existingVehicle == null |
| | | || !Objects.equals(existingVehicle.getVehicleVin(), xpVehicle.getVehicleVin()); |
| | | if (vinChanged || existingVehicle == null || StringUtils.isBlank(existingVehicle.getXpuId())) { |
| | | // 仅在 VIN 变更或原 XPUID 为空时才重新绑定 XPUID,避免不必要的远程调用 |
| | | String vin = xpVehicle.getVehicleVin(); |
| | | R<String> xpuIdByVin = xpuVinClient.getXpuIdByVin(vin); |
| | | if(200 != xpuIdByVin.getCode()){ |
| | | throw new RuntimeException(xpuIdByVin.getMsg()); |
| | | } |
| | | String xpuid = xpuIdByVin.getData(); |
| | | xpVehicle.setXpuId(xpuid); |
| | | } else { |
| | | xpVehicle.setXpuId(existingVehicle.getXpuId()); |
| | | } |
| | | this.updateById(xpVehicle); |
| | | } |
| | | |
| | |
| | | if (StringUtils.isNotBlank(vehicleColor) && vehicleColor.length() > 2) { |
| | | throw new ServiceException("车辆颜色长度不能超过2", I18nKeyConstant.VEHICLE_COLOR_INVALID, new Object[]{vehicleColor}); |
| | | } |
| | | |
| | | boolean vehicleCodeExists = lambdaQuery() |
| | | .eq(XpVehicle::getVehicleCode, vehicleCode) |
| | | List<XpVehicle> duplicates = lambdaQuery() |
| | | .ne(excludeId != null, XpVehicle::getId, excludeId) |
| | | .last("limit 1") |
| | | .one() != null; |
| | | .and(w -> w.eq(XpVehicle::getVehicleCode, vehicleCode) |
| | | .or() |
| | | .eq(XpVehicle::getVehicleVin, vehicleVin) |
| | | .or() |
| | | .eq(XpVehicle::getPlateNumber, plateNumber)) |
| | | .last("limit 3") |
| | | .list(); |
| | | if (CollectionUtils.isEmpty(duplicates)) { |
| | | return; |
| | | } |
| | | |
| | | boolean vehicleCodeExists = duplicates.stream().anyMatch(v -> vehicleCode.equals(v.getVehicleCode())); |
| | | if (vehicleCodeExists) { |
| | | throw new ServiceException("车辆编码已存在", I18nKeyConstant.VEHICLE_CODE_EXISTS, new Object[]{vehicleCode}); |
| | | } |
| | | |
| | | boolean vehicleVinExists = lambdaQuery() |
| | | .eq(XpVehicle::getVehicleVin, vehicleVin) |
| | | .ne(excludeId != null, XpVehicle::getId, excludeId) |
| | | .last("limit 1") |
| | | .one() != null; |
| | | boolean vehicleVinExists = duplicates.stream().anyMatch(v -> vehicleVin.equals(v.getVehicleVin())); |
| | | if (vehicleVinExists) { |
| | | throw new ServiceException("车辆VIN码已存在", I18nKeyConstant.VEHICLE_VIN_EXISTS, new Object[]{vehicleVin}); |
| | | } |
| | | |
| | | boolean plateNumberExists = lambdaQuery() |
| | | .eq(XpVehicle::getPlateNumber, plateNumber) |
| | | .ne(excludeId != null, XpVehicle::getId, excludeId) |
| | | .last("limit 1") |
| | | .one() != null; |
| | | boolean plateNumberExists = duplicates.stream().anyMatch(v -> plateNumber.equals(v.getPlateNumber())); |
| | | if (plateNumberExists) { |
| | | throw new ServiceException("车牌号已存在", I18nKeyConstant.VEHICLE_PLATE_EXISTS, new Object[]{plateNumber}); |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @Transactional |
| | | @ShardingSphereTransactionType(TransactionType.BASE) |
| | | public void improveInfo(VehicleImproveInfoDTO dto) { |
| | | // 校验已填写的时间字段是否在有效范围内 |
| | | validateTimeFields(dto); |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void batchOperation(String idStr) { |
| | | if (StringUtils.isBlank(idStr)) { |
| | | return; |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void batchStock(String idStr) { |
| | | if (StringUtils.isBlank(idStr)) { |
| | | return; |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void batchSetElectronic(List<Long> ids, Long electronicId) { |
| | | if (CollectionUtils.isEmpty(ids)) { |
| | | return; |
| | |
| | | if (CollUtil.isNotEmpty(list)) { |
| | | LocalDate today = LocalDate.now(); |
| | | List<Long> expiredVehicleIds = new ArrayList<>(); |
| | | List<Long> VehicleIds = new ArrayList<>(); |
| | | |
| | | for (XpVehicle vehicle : list) { |
| | | // 检查是否有任意一项过期(精确到 yyyy-MM-dd) |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void importVehicles(List<XpVehicleImportExcel> importList) { |
| | | if (CollectionUtils.isEmpty(importList)) { |
| | | return; |
| | |
| | | .like(StringUtils.isNotBlank(query.getVehicleVin()), XpVehicle::getVehicleVin, query.getVehicleVin()) |
| | | .like(StringUtils.isNotBlank(query.getPlateNumber()), XpVehicle::getPlateNumber, query.getPlateNumber()) |
| | | .eq(Objects.nonNull(query.getOperatingStatus()), XpVehicle::getOperatingStatus, query.getOperatingStatus()) |
| | | .eq(Objects.nonNull(query.getElectronicId()), XpVehicle::getElectronicId, query.getOperatingStatus()); |
| | | .eq(Objects.nonNull(query.getElectronicId()), XpVehicle::getElectronicId, query.getElectronicId()); |
| | | if (Objects.nonNull(query.getStartTime())) { |
| | | wrapper.ge(XpVehicle::getAnnualInspectionDate, LocalDateTime.of(query.getStartTime(), LocalTime.MIN)); |
| | | } |
| | |
| | | throw new ServiceException("未查询到有效订单信息", I18nKeyConstant.ORDER_NOT_EXISTS); |
| | | } |
| | | XpVehicle xpVehicle = this.getById(xpOrder.getVehicleId()); |
| | | if (Objects.isNull(xpVehicle)) { |
| | | if (Objects.isNull(xpVehicle) || Objects.isNull(xpVehicle.getVehicleVin())) { |
| | | throw new ServiceException("未查询到有效车辆信息", I18nKeyConstant.VEHICLE_NOT_EXISTS); |
| | | } |
| | | try { |
| | |
| | | pageInfo.setRecords(page.getRecords()); |
| | | return pageInfo; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Boolean getVehicleTrunkOpenStatus(Long uid, Long id) { |
| | | XpVehicle xpVehicle = this.getById(id); |
| | | try { |
| | | VehicleTemperatureDto vehicleTemperatureDto = vehicleControlUtil.queryVehicleTemperature(String.valueOf(uid), xpVehicle.getVehicleVin()); |
| | | log.info("查询车辆温度成功:{}", vehicleTemperatureDto); |
| | | VehicleStateVo trunkAjarCloseSt = vehicleTemperatureDto.getStateMap().get("trunkAjarCloseSt"); |
| | | if(null == trunkAjarCloseSt){ |
| | | return false; |
| | | } |
| | | return trunkAjarCloseSt.getValue().equals("1"); |
| | | } catch (Exception e) { |
| | | log.error("查询车辆温度失败", e); |
| | | return false; |
| | | } |
| | | } |
| | | } |