xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpOrderClientFallbackFactory.java
@@ -79,6 +79,12 @@ } @Override public R<Integer> todayCancellationCount(Long userId) { log.error("获取当日取消订单次数失败,原因: {}", cause.getMessage()); return R.fail("获取当日取消订单次数失败"); } @Override public R<Integer> countActiveOrdersByCityId(Long cityId) { log.error("查询进行中订单数量失败,原因: {}", cause.getMessage()); return R.ok(0); xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/order/XpTestOrderClientFallbackFactory.java
@@ -27,6 +27,13 @@ log.error("更新订单状态失败:{}", cause.getMessage()); return R.fail("更新订单状态失败"); } @Override public R<?> cancelTestOrderById(Long orderId) { log.error("取消订单失败:{}", cause.getMessage()); return R.fail("取消订单失败"); } }; } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpOrderClient.java
@@ -85,6 +85,17 @@ @PostMapping("/inner/order/getOrderNum") R<Integer> getOrderNum(@RequestBody GetOrderNumDto dto); /** * 当日取消订单次数 * * @param * @return 订单数量 */ @PostMapping("/inner/order/todayCancellationCount") R<Integer> todayCancellationCount(@RequestParam Long userId); /** * 查询指定城市进行中的订单数量(status=1) * xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/order/XpTestOrderClient.java
@@ -33,4 +33,14 @@ @PostMapping("/inner/v1/testOrder/updateOrderStatus") R<String> updateOrderStatus(@RequestParam Long orderId, @RequestParam Integer status); /** * 根据订单ID查询取消订单 * * @param orderId * @return */ @PostMapping("/inner/testOrder/cancelTestOrderById") R<?> cancelTestOrderById(@RequestParam Long orderId); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/OrderType.java
@@ -16,4 +16,8 @@ * 测试订单 */ String TEST_ORDER = "test_order"; /** * 测试订单 */ String TEST_CRUISE_ORDER = "test_cruise_order"; } xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
@@ -19,7 +19,6 @@ import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.order.XpOrder;import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.OrderType; import com.xiaopeng.api.vo.SystemEventType; import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; import com.xiaopeng.api.vo.automaticPilot.protobuf.*; @@ -104,6 +103,7 @@ taskBuilder.addOrderPhase(OrderPhase.ROUTE_TO_CRUISE); taskListBuilder.addTasks(taskBuilder.build()); }else if(dto.getOrderType().equals(com.xiaopeng.api.vo.OrderType.USER_ORDER)){ //乘客单 for (int i = 1; i < 3; i++) { RtTask.Builder taskBuilder = RtTask.newBuilder(); taskBuilder.setOrderId(dto.getOrderId().toString()); @@ -162,6 +162,7 @@ taskListBuilder.addTasks(taskBuilder.build()); } }else if(dto.getOrderType().equals(com.xiaopeng.api.vo.OrderType.TEST_ORDER)){ //测试单 for (int i = 1; i < 3; i++) { RtTask.Builder taskBuilder = RtTask.newBuilder(); taskBuilder.setOrderId(dto.getOrderId().toString()); @@ -219,12 +220,44 @@ } taskListBuilder.addTasks(taskBuilder.build()); } }else if(dto.getOrderType().equals(com.xiaopeng.api.vo.OrderType.TEST_CRUISE_ORDER)){ //测试单巡游单 RtTask.Builder taskBuilder = RtTask.newBuilder(); taskBuilder.setOrderId(dto.getOrderId().toString()); taskBuilder.setTaskId(snowflake.nextId() + ""); taskBuilder.setTaskType(OrderType.ORDER_TYPE_CRUISE); //构建起点坐标数据 pointBuilderStart.setWaypointId(dto.getOrderId() + "-001"); pointBuilderStart.setPointType(PointType.START_POINT); pointBuilderStart.setSequence(1); pointBuilderStart.setActionType(ActionType.ACTION_UNSPECIFIED); GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder(); geoPointBuilder.setLatitude(dto.getStartLatitude()); geoPointBuilder.setLongitude(dto.getStartLongitude()); pointBuilderStart.setPoint(geoPointBuilder.build()); taskBuilder.addPoints(pointBuilderStart); //构建终点数据 pointBuilderEnd.setWaypointId(dto.getOrderId() + "-002"); pointBuilderEnd.setPointType(PointType.CRUISE_END_POINT); pointBuilderEnd.setSequence(2); pointBuilderEnd.setActionType(ActionType.DRIVE_THROUGH); geoPointBuilder = GeoPoint.newBuilder(); geoPointBuilder.setLatitude(dto.getEndLatitude()); geoPointBuilder.setLongitude(dto.getEndLongitude()); pointBuilderEnd.setPoint(geoPointBuilder.build()); taskBuilder.addPoints(pointBuilderEnd); taskBuilder.setSequence(1); taskBuilder.addOrderPhase(OrderPhase.ROUTE_TO_CRUISE); taskListBuilder.addTasks(taskBuilder.build()); } long sequence = snowflake.nextId(); MqttPublishDto mqttPublishDto = xpuUtil.cloudCreateOrder(taskListBuilder.build(), dto.getVin(),sequence); //先将车辆修改状态,防止在异步通知之前被其他订单选中 if (!dto.getOrderId().contains("XU") && mqttPublishDto.getCode()== 200) { if(!dto.getOrderType().equals(com.xiaopeng.api.vo.OrderType.CRUISE_ORDER) && !dto.getOrderType().equals(com.xiaopeng.api.vo.OrderType.TEST_CRUISE_ORDER) && mqttPublishDto.getCode()== 200){ // 修改车子为接单状态 xpVehicleClient.updateVehicleStatus(new UpdateVehicleStateDto(dto.getVin(), 1)); } xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -6,6 +6,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.util.JsonFormat; import com.xiaopeng.api.dto.automaticPilot.MqttPublishDto; import com.xiaopeng.api.dto.automaticPilot.PushOrderDto; import com.xiaopeng.api.dto.automaticPilot.VehicleEventDTO; import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; import com.xiaopeng.api.dto.operation.CruisePointDto; @@ -423,7 +424,7 @@ if (abnormalReason == AbnormalReason.FAULT) { log.info("车辆故障,开始处理故障"); String orderId = systemRuntimeStatus.getRunningOrderStatusInfo().getOrderId(); if(!orderId.contains("XU")){ if(orderId.contains("XU")){ //巡游订单,需要关闭订单 xpCruiseOrderClient.cancelCruiseOrderById(Long.parseLong(orderId.substring(2))); XpCruiseOrder cruiseOrder = xpCruiseOrderClient.getCruiseOrder(Long.parseLong(orderId.substring(2))).getData(); @@ -435,7 +436,19 @@ vehicle1.setId(vehicle.getId()); xpVehicleClient.updateVehicleById(vehicle1); } }else{ }else if(orderId.contains("TEST")){ //测试订单故障则取消订单 XpTestOrder testOrder = testOrderClient.queryOrderById(Long.parseLong(orderId.substring(4))).getData(); vehicle = xpVehicleClient.queryById(testOrder.getVehicleId()).getData(); if (vehicle != null) { // 修改车辆状态 XpVehicle vehicle1 = new XpVehicle(); vehicle1.setOperatingStatus(4); vehicle1.setId(vehicle.getId()); xpVehicleClient.updateVehicleById(vehicle1); log.info("车辆故障,车辆状态修改0 {}", vehicle.getPlateNumber()); } }else { //正常订单 XpOrder xpOrder = xpOrderClient.queryOrderById(Long.parseLong(orderId)).getData(); vehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/service/impl/XpPricingServiceImpl.java
@@ -489,15 +489,11 @@ } // 判断当天取消的次数 后台配置 redis 查询 Object cancelOrder = redisService.getCacheObject("CANCEL_ORDER_" + uid); log.info("取消次数:{}", cancelOrder); // 静默处理 boolean isSilent = false; if (cancelOrder != null) { Integer num = Integer.valueOf(cancelOrder.toString()); if (num >= cancelCount) { isSilent = true; } Integer num = xpOrderClient.todayCancellationCount(Long.valueOf(uid)).getData(); if (num >= cancelCount) { isSilent = true; } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/constant/I18nKeyConstant.java
@@ -10,4 +10,6 @@ String TASK_NOT_EXIST = "task.not.exist"; String VEHICLE_NOT_EXIST = "vehicle.not.exist"; String REPAIR_MONEY_TOO_LONG = "repair.money.too.long"; String TASK_SAVE_ERROR = "task.save.error"; String TASK_VEHICLE_NOT_EXIST = "task.vehicle.not.exist"; } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpChargingRecordController.java
@@ -3,6 +3,7 @@ import com.xiaopeng.api.feignClient.account.XpOperationUserClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.maintenance.XpChargingRecord; import com.xiaopeng.maintenance.model.query.XpChargingRecordPageQuery; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.web.page.PageInfo; @@ -66,9 +67,9 @@ public R<String> stopCharging(@RequestBody XpChargingRecordStopDTO dto) { Long id = tokenService.getLoginOperationUser().getId(); xpChargingRecordService.stopCharging(dto, id); XpChargingRecord chargingRecord = xpChargingRecordService.stopCharging(dto, id); //更新任务状态 xpTaskService.updateTaskStatus(dto.getTaskId(), 2, id); xpTaskService.updateTaskStatus(chargingRecord.getTaskId(), 2, id); return R.ok(); } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/vo/TaskChargingDetailVO.java
@@ -55,6 +55,7 @@ private String startChargingPicture; @ApiModelProperty(value = "开始充电时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private LocalDateTime startTime; @ApiModelProperty(value = "结束剩余电量") @@ -64,6 +65,7 @@ private String endChargingPicture; @ApiModelProperty(value = "结束充电时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private LocalDateTime endTime; @ApiModelProperty(value = "开始充电操作人") xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/IXpChargingRecordService.java
@@ -35,7 +35,7 @@ * @param dto * @param id */ void stopCharging(XpChargingRecordStopDTO dto, Long id); XpChargingRecord stopCharging(XpChargingRecordStopDTO dto, Long id); /** * 充电记录详情 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpChargingRecordServiceImpl.java
@@ -84,7 +84,7 @@ } @Override public void stopCharging(XpChargingRecordStopDTO dto, Long id) { public XpChargingRecord stopCharging(XpChargingRecordStopDTO dto, Long id) { // 查询车辆充电记录 进行修改 XpChargingRecord xpChargingRecord = this.getById(dto.getId()); // 查询车辆信息 @@ -104,6 +104,7 @@ } } this.updateById(xpChargingRecord); return xpChargingRecord; } @Override xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
@@ -224,37 +224,33 @@ String code = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); xpTask.setTaskCode(code); xpTask.setTaskCategory(2); String[] split = dto.getTaskTypeId().split(","); List<String> typeIds = new ArrayList<>(); for (String s : split) { typeIds.add(s.trim()); } StringBuilder temp = new StringBuilder(dto.getTaskTypeId()); List<Long> children = typeIds.stream().map(Long::parseLong).collect(Collectors.toList()); List<Long> parentIds = errorTypeMapper.selectList(new LambdaQueryWrapper<XpErrorType>() .in(XpErrorType::getId, children)).stream().map(XpErrorType::getParentId).distinct().collect(Collectors.toList()); for (Long parentId : parentIds) { temp.append(",").append(parentId); } xpTask.setTaskTypeId(temp.toString()); xpTask.setTaskTypeId(normalizeAccidentTaskTypeId(dto.getTaskTypeId())); xpTask.setTaskUrgencyLevel(dto.getTaskUrgencyLevel()); xpTask.setTaskDescription(dto.getTaskDescription()); xpTask.setTaskImage(dto.getTaskImage()); xpTask.setVehicleId(dto.getId()); XpVehicle vehicle = xpVehicleClient.queryById(xpTask.getVehicleId()).getData(); // if (vehicle!=null){ // VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vehicle.getVehicleVin())), VehiclePosition.class); // if (vehiclePosition != null) { // double x = vehiclePosition.getPoint().getX(); // double y = vehiclePosition.getPoint().getY(); // xpTask.setVehicleLon(new BigDecimal(x)); // xpTask.setVehicleLat(new BigDecimal(y)); // } // } if (Objects.isNull(vehicle)) { throw new ServiceException("上报失败,未获取到车辆信息", I18nKeyConstant.TASK_VEHICLE_NOT_EXIST); } VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vehicle.getVehicleVin())), VehiclePosition.class); if (Objects.isNull(vehiclePosition)) { log.error("事故上报未获取到车辆当前定位"); throw new ServiceException("获取车辆实时定位信息失败,请稍后重试", I18nKeyConstant.TASK_SAVE_ERROR); } xpTask.setVehicleLon(new BigDecimal(vehiclePosition.getPoint().getX())); xpTask.setVehicleLat(new BigDecimal(vehiclePosition.getPoint().getY())); Map<String, String> geocode = gdMapGeocodingUtil.geocode(xpTask.getVehicleLon().toString(), xpTask.getVehicleLat().toString()); String address = geocode == null ? null : geocode.get("address"); if (StringUtils.isBlank(address)) { log.error("事故上报通过车辆定位从高德获取地址信息失败"); throw new ServiceException("获取车辆实时定位信息失败,请稍后重试", I18nKeyConstant.TASK_SAVE_ERROR); } xpTask.setVehicleLocation(address); // 临时处理 xpTask.setVehicleLon(new BigDecimal("104.055683")); xpTask.setVehicleLat(new BigDecimal("30.585991")); xpTask.setVehicleLocation("四川省成都市武侯区石羊街道天府新谷"); // xpTask.setVehicleLon(new BigDecimal("104.055683")); // xpTask.setVehicleLat(new BigDecimal("30.585991")); // xpTask.setVehicleLocation("四川省成都市武侯区石羊街道天府新谷"); xpTask.setVehicleId(dto.getId()); xpTask.setReportUserId(xpOperationsUser.getId()); xpTask.setReportTime(LocalDateTime.now()); @@ -323,38 +319,58 @@ } // 构建通知内容 String content = String.format("车辆%s在%s发生了紧急事故,请在%d分钟内到达现场!", plateNumber, xpTask.getVehicleLocation(), processingTimeLimit); String bodyJson = buildAccidentPushBodyJson(content, xpTask); // 构建通知记录(包含 notificationExt) List<XpOperationsUserNotification> notifications = data.stream().map(item -> { XpOperationsUserNotification notification = new XpOperationsUserNotification(); notification.setOperationsUserId(item.getId()); notification.setNotificationType(NotificationTypeEnum.ACCIDENT_NEW.getCode()); notification.setNotificationContent(content); notification.setDataId(xpTask.getId()); notification.setReadStatus(0); notification.setNotificationExt(bodyJson); return notification; }).collect(Collectors.toList()); // 批量保存通知记录 xpOperationUserNotificationClient.addNotificationBatch(notifications); log.info("事故通知记录保存成功,共 {} 条", notifications.size()); // 按设备类型分组发送阿里云推送 Map<Integer, List<XpOperationsUser>> operationUserMap = data.stream() .filter(u -> u.getDeviceType() != null && u.getPhoneNumber() != null) .collect(Collectors.groupingBy(XpOperationsUser::getDeviceType)); for (Map.Entry<Integer, List<XpOperationsUser>> entry : operationUserMap.entrySet()) { pushAliMessage(entry.getValue(), content, xpTask); } String content = buildAccidentNotificationContent(xpTask, plateNumber, processingTimeLimit); saveAndPushAccidentNotification(data, content, xpTask); } catch (Exception e) { log.error("发送事故通知失败,任务ID={}", xpTask.getId(), e); } }); executor.shutdown(); } /** * 异步发送事故任务分配通知 * * @param xpTask 任务信息 * @param handlerUserId 当前分配的处理人 * @param plateNumber 车牌号 * @param processingTimeLimit 处理时限(分钟) */ private void sendAssignedAccidentNotificationAsync(XpTask xpTask, Long handlerUserId, String plateNumber, Integer processingTimeLimit) { ThreadPoolExecutor executor = new ThreadPoolExecutor( 1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>() ); executor.execute(() -> { try { R<List<XpOperationsUser>> xpOperationUserResult = xpOperationUserClient.listByIds(Collections.singletonList(handlerUserId)); List<XpOperationsUser> data = xpOperationUserResult == null ? Collections.emptyList() : xpOperationUserResult.getData(); if (CollUtil.isEmpty(data)) { return; } String content = buildAccidentNotificationContent(xpTask, plateNumber, processingTimeLimit); saveAndPushAccidentNotification(data, content, xpTask); } catch (Exception e) { log.error("发送事故任务分配通知失败,任务ID={}, handlerUserId={}", xpTask.getId(), handlerUserId, e); } }); executor.shutdown(); } /** * 构建事故通知文案 * * @param xpTask 任务信息 * @param plateNumber 车牌号 * @param processingTimeLimit 处理时限(分钟) * @return 通知内容 */ private String buildAccidentNotificationContent(XpTask xpTask, String plateNumber, Integer processingTimeLimit) { return String.format("车辆%s在%s发生了紧急事故,请在%d分钟内到达现场!", plateNumber, xpTask.getVehicleLocation(), processingTimeLimit); } /** @@ -370,6 +386,40 @@ param.put("type", TaskTypeNotificationEnum.ACCIDENT_TASK.getCode()); param.put("id", xpTask.getId().toString()); return JSONObject.toJSONString(param); } /** * 保存事故通知记录并发送阿里云推送 * * @param data 接收通知的运维人员 * @param content 通知内容 * @param xpTask 任务信息 */ private void saveAndPushAccidentNotification(List<XpOperationsUser> data, String content, XpTask xpTask) { String bodyJson = buildAccidentPushBodyJson(content, xpTask); List<XpOperationsUserNotification> notifications = data.stream().map(item -> { XpOperationsUserNotification notification = new XpOperationsUserNotification(); notification.setOperationsUserId(item.getId()); notification.setNotificationType(NotificationTypeEnum.ACCIDENT_NEW.getCode()); notification.setNotificationContent(content); notification.setDataId(xpTask.getId()); notification.setReadStatus(0); notification.setNotificationExt(bodyJson); return notification; }).collect(Collectors.toList()); if (CollUtil.isNotEmpty(notifications)) { xpOperationUserNotificationClient.addNotificationBatch(notifications); log.info("事故通知记录保存成功,共 {} 条", notifications.size()); } Map<Integer, List<XpOperationsUser>> operationUserMap = data.stream() .filter(u -> u.getDeviceType() != null && StringUtils.isNotBlank(u.getPhoneNumber())) .collect(Collectors.groupingBy(XpOperationsUser::getDeviceType)); for (Map.Entry<Integer, List<XpOperationsUser>> entry : operationUserMap.entrySet()) { pushAliMessage(entry.getValue(), content, xpTask); } } /** @@ -606,7 +656,7 @@ res.setTaskTypeId(task.getTaskTypeId()); res.setStatus(task.getStatus()); XpChargingRecord chargingRecord = chargingRecordMapper.selectOne(new LambdaQueryWrapper<XpChargingRecord>() .eq(XpChargingRecord::getTaskId, id).last("limit 1")); .eq(XpChargingRecord::getTaskId, id).last("limit 1").orderByDesc(XpChargingRecord::getCreateTime)); if (chargingRecord != null) { res.setStartRemainingBattery(chargingRecord.getStartRemainingBattery()); @@ -1335,60 +1385,7 @@ taskManagementPageListVO.setHandleUserName(handleUserName.toString()); } } if (taskManagementPageListVO.getTaskCategory() == 1) { switch (taskManagementPageListVO.getTaskTypeId()) { case "1": taskManagementPageListVO.setTaskTypeName("车辆检查"); break; case "2": taskManagementPageListVO.setTaskTypeName("车辆充电"); break; case "3": taskManagementPageListVO.setTaskTypeName("车辆整备"); break; case "4": taskManagementPageListVO.setTaskTypeName("整备洗车"); break; case "5": taskManagementPageListVO.setTaskTypeName("车辆维修"); break; case "6": taskManagementPageListVO.setTaskTypeName("车辆保养"); break; case "7": taskManagementPageListVO.setTaskTypeName("车辆保险到期"); break; case "8": taskManagementPageListVO.setTaskTypeName("车辆年检到期"); break; case "9": taskManagementPageListVO.setTaskTypeName("车辆运营资质到期"); break; default: taskManagementPageListVO.setTaskTypeName(""); break; } } else { StringBuilder taskTypeName = new StringBuilder(); String[] typeIds = taskManagementPageListVO.getTaskTypeId().split(","); List<XpErrorType> xpErrorTypes = errorTypeMapper.selectList(new LambdaQueryWrapper<XpErrorType>() .in(XpErrorType::getId, Arrays.asList(typeIds)).orderByAsc(XpErrorType::getParentId)); List<XpErrorType> parents = new ArrayList<>(); for (XpErrorType xpErrorType : xpErrorTypes) { if (xpErrorType.getParentId() == 0) { parents.add(xpErrorType); } } for (XpErrorType parent : parents) { List<XpErrorType> children = xpErrorTypes.stream().filter(e -> e.getParentId().equals(parent.getId())).collect(Collectors.toList()); taskTypeName.append(parent.getErrorName()).append(">"); for (XpErrorType child : children) { taskTypeName.append(child.getErrorName()).append(";"); } } taskManagementPageListVO.setTaskTypeName(taskTypeName.substring(0, taskTypeName.length() - 1)); } taskManagementPageListVO.setTaskTypeName(resolveManagementTaskTypeName(taskManagementPageListVO)); } pageInfo.setRecords(list); return pageInfo; @@ -1409,62 +1406,174 @@ taskManagementPageListVO.setHandleUserName(handleUserName.toString()); } } if (taskManagementPageListVO.getTaskCategory() == 1) { switch (taskManagementPageListVO.getTaskTypeId()) { case "1": taskManagementPageListVO.setTaskTypeName("车辆检查"); break; case "2": taskManagementPageListVO.setTaskTypeName("车辆充电"); break; case "3": taskManagementPageListVO.setTaskTypeName("车辆整备"); break; case "4": taskManagementPageListVO.setTaskTypeName("整备洗车"); break; case "5": taskManagementPageListVO.setTaskTypeName("车辆维修"); break; case "6": taskManagementPageListVO.setTaskTypeName("车辆保养"); break; case "7": taskManagementPageListVO.setTaskTypeName("车辆保险到期"); break; case "8": taskManagementPageListVO.setTaskTypeName("车辆年检到期"); break; case "9": taskManagementPageListVO.setTaskTypeName("车辆运营资质到期"); break; default: taskManagementPageListVO.setTaskTypeName(""); break; } } else { StringBuilder taskTypeName = new StringBuilder(); String[] typeIds = taskManagementPageListVO.getTaskTypeId().split(","); List<XpErrorType> xpErrorTypes = errorTypeMapper.selectList(new LambdaQueryWrapper<XpErrorType>() .in(XpErrorType::getId, Arrays.asList(typeIds)).orderByAsc(XpErrorType::getParentId)); List<XpErrorType> parents = new ArrayList<>(); for (XpErrorType xpErrorType : xpErrorTypes) { if (xpErrorType.getParentId() == 0) { parents.add(xpErrorType); } } for (XpErrorType parent : parents) { List<XpErrorType> children = xpErrorTypes.stream().filter(e -> e.getParentId().equals(parent.getId())).collect(Collectors.toList()); taskTypeName.append(parent.getErrorName()).append(">"); for (XpErrorType child : children) { taskTypeName.append(child.getErrorName()).append(";"); } } taskManagementPageListVO.setTaskTypeName(taskTypeName.substring(0, taskTypeName.length() - 1)); } taskManagementPageListVO.setTaskTypeName(resolveManagementTaskTypeName(taskManagementPageListVO)); } return list; } private String resolveManagementTaskTypeName(TaskManagementPageListVO taskManagementPageListVO) { if (Integer.valueOf(1).equals(taskManagementPageListVO.getTaskCategory())) { return resolveRoutineTaskTypeName(taskManagementPageListVO.getTaskTypeId()); } if (Integer.valueOf(2).equals(taskManagementPageListVO.getTaskCategory())) { return resolveAccidentTaskTypeName(taskManagementPageListVO.getTaskTypeId()); } return ""; } private String resolveRoutineTaskTypeName(String taskTypeId) { if (StringUtils.isBlank(taskTypeId)) { return ""; } switch (taskTypeId) { case "1": return "车辆检查"; case "2": return "车辆充电"; case "3": return "车辆整备"; case "4": return "整备洗车"; case "5": return "车辆维修"; case "6": return "车辆保养"; case "7": return "车辆保险到期"; case "8": return "车辆年检到期"; case "9": return "车辆运营资质到期"; default: return ""; } } private String resolveAccidentTaskTypeName(String taskTypeId) { List<Long> orderedTypeIds = parseAccidentTaskTypeIds(taskTypeId); if (orderedTypeIds.isEmpty()) { return ""; } Map<Long, XpErrorType> errorTypeMap = getAccidentErrorTypeMap(orderedTypeIds); if (errorTypeMap.isEmpty()) { return ""; } LinkedHashSet<Long> orderedParentIds = new LinkedHashSet<>(); LinkedHashMap<Long, List<XpErrorType>> childrenByParent = new LinkedHashMap<>(); for (Long typeId : orderedTypeIds) { XpErrorType errorType = errorTypeMap.get(typeId); if (errorType == null || StringUtils.isBlank(errorType.getErrorName())) { continue; } if (isTopLevelErrorType(errorType)) { orderedParentIds.add(errorType.getId()); continue; } Long parentId = errorType.getParentId(); if (parentId == null) { continue; } orderedParentIds.add(parentId); childrenByParent.computeIfAbsent(parentId, key -> new ArrayList<>()).add(errorType); } List<String> displayNames = new ArrayList<>(); for (Long parentId : orderedParentIds) { XpErrorType parent = errorTypeMap.get(parentId); List<XpErrorType> children = childrenByParent.get(parentId); if (CollectionUtils.isEmpty(children)) { if (parent != null && StringUtils.isNotBlank(parent.getErrorName())) { displayNames.add(parent.getErrorName()); } continue; } String parentName = parent == null ? null : parent.getErrorName(); for (XpErrorType child : children) { if (StringUtils.isBlank(parentName)) { displayNames.add(child.getErrorName()); } else { displayNames.add(parentName + ">" + child.getErrorName()); } } } return String.join(";", displayNames); } private Map<Long, XpErrorType> getAccidentErrorTypeMap(List<Long> orderedTypeIds) { Map<Long, XpErrorType> errorTypeMap = getErrorTypeMap(orderedTypeIds); if (errorTypeMap.isEmpty()) { return errorTypeMap; } Set<Long> missingParentIds = new LinkedHashSet<>(); for (Long typeId : orderedTypeIds) { XpErrorType errorType = errorTypeMap.get(typeId); if (errorType == null || isTopLevelErrorType(errorType)) { continue; } if (errorType.getParentId() != null && !errorTypeMap.containsKey(errorType.getParentId())) { missingParentIds.add(errorType.getParentId()); } } if (!missingParentIds.isEmpty()) { errorTypeMap.putAll(getErrorTypeMap(missingParentIds)); } return errorTypeMap; } private boolean isTopLevelErrorType(XpErrorType errorType) { return errorType.getParentId() == null || errorType.getParentId() == 0L; } private String normalizeAccidentTaskTypeId(String taskTypeId) { List<Long> orderedTypeIds = parseAccidentTaskTypeIds(taskTypeId); if (orderedTypeIds.isEmpty()) { return taskTypeId; } LinkedHashSet<Long> normalizedTypeIds = new LinkedHashSet<>(orderedTypeIds); Map<Long, XpErrorType> errorTypeMap = getErrorTypeMap(orderedTypeIds); for (Long typeId : orderedTypeIds) { XpErrorType errorType = errorTypeMap.get(typeId); if (errorType == null || errorType.getParentId() == null || errorType.getParentId() == 0L) { continue; } normalizedTypeIds.add(errorType.getParentId()); } return normalizedTypeIds.stream().map(String::valueOf).collect(Collectors.joining(",")); } private List<Long> parseAccidentTaskTypeIds(String taskTypeId) { if (StringUtils.isBlank(taskTypeId)) { return Collections.emptyList(); } LinkedHashSet<Long> typeIds = new LinkedHashSet<>(); for (String typeId : taskTypeId.split(",")) { if (StringUtils.isBlank(typeId)) { continue; } try { typeIds.add(Long.parseLong(typeId.trim())); } catch (NumberFormatException ignored) { } } return new ArrayList<>(typeIds); } private Map<Long, XpErrorType> getErrorTypeMap(Collection<Long> typeIds) { if (CollectionUtils.isEmpty(typeIds)) { return Collections.emptyMap(); } return errorTypeMapper.selectBatchIds(typeIds).stream() .filter(Objects::nonNull) .collect(Collectors.toMap(XpErrorType::getId, errorType -> errorType, (left, right) -> left)); } @Override @@ -1523,16 +1632,41 @@ @Override public R assigneeTask(Long id, Long handlerUserId, Long assigneeUserId) { XpTask task = this.getById(id); // 查询规则 任务结束时间从任务分配时开始计算 XpTaskRule taskRule = xpTaskRuleMapper.selectOne(null); if (taskRule != null) { task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); if (task == null) { throw new ServiceException( "任务不存在", I18nKeyConstant.TASK_NOT_EXIST ); } boolean isAccidentTask = Integer.valueOf(2).equals(task.getTaskCategory()); Long vehicleId = task.getVehicleId(); Integer processingTimeLimit = null; String plateNumber = ""; if (isAccidentTask) { // 查询规则 任务结束时间从任务分配时开始计算 XpTaskRule taskRule = xpTaskRuleMapper.selectOne(null); if (taskRule != null) { processingTimeLimit = taskRule.getProcessingTimeLimit(); task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); } if (vehicleId != null) { XpVehicle vehicle = xpVehicleClient.queryById(vehicleId).getData(); if (vehicle != null && StringUtils.isNotBlank(vehicle.getPlateNumber())) { plateNumber = vehicle.getPlateNumber(); } } } else { task.setEndTime(LocalDateTime.now().plusDays(3)); } task.setAssigneeTime(LocalDateTime.now()); task.setHandleUserId(handlerUserId.toString()); task.setVehicleId(null); task.setAssigneeUserId(assigneeUserId); this.updateById(task); if (isAccidentTask && processingTimeLimit != null) { sendAssignedAccidentNotificationAsync(task, handlerUserId, plateNumber, processingTimeLimit); } return R.ok(); } @@ -1540,6 +1674,7 @@ public void saveTask(SaveErrorTaskDto dto, Long reportUserId) { List<XpTask> saveTask = new ArrayList<>(); String normalizedTaskTypeId = normalizeAccidentTaskTypeId(dto.getTaskTypeId()); for (Long vehicleId : dto.getVehicleIds()) { XpTask task = new XpTask(); BeanUtils.copyProperties(dto, task); @@ -1549,7 +1684,7 @@ String code = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); task.setTaskCode(code); task.setTaskCategory(2); task.setTaskTypeId(dto.getTaskTypeId()); task.setTaskTypeId(normalizedTaskTypeId); task.setTaskUrgencyLevel(dto.getTaskUrgencyLevel()); task.setTaskDescription(dto.getTaskDescription()); task.setTaskImage(dto.getTaskImage()); @@ -1585,19 +1720,7 @@ I18nKeyConstant.VEHICLE_NOT_EXIST ); } String vehiclePicture = vehicle.getVehiclePictures(); if (vehicle.getVehiclePictures() != null) { JSONObject jsonObject = JSONObject.parseObject(vehicle.getVehiclePictures()); // 1 String downloadUrl = jsonObject.getString("url"); try { downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true); } catch (UnsupportedEncodingException e) { log.error("获取图片下载地址失败", e); } jsonObject.put("url", downloadUrl); vehiclePicture = jsonObject.toJSONString(); } String vehiclePicture = aliOssDownloadUtil.getPictureJSONObject(vehicle.getVehiclePictures()); if (task.getTaskCategory() == 1) { // 常规任务 @@ -1613,19 +1736,7 @@ taskManagementDetectionDetailVO.setVehicleCode(vehicle.getVehicleCode()); taskManagementDetectionDetailVO.setVehicleVin(vehicle.getVehicleVin()); taskManagementDetectionDetailVO.setVehicleLocation(task.getVehicleLocation()); if (vehicle.getVehiclePictures() != null) { JSONObject jsonObject = JSONObject.parseObject(vehicle.getVehiclePictures()); // 1 String downloadUrl = jsonObject.getString("url"); try { downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true); } catch (UnsupportedEncodingException e) { log.error("获取图片下载地址失败", e); } jsonObject.put("url", downloadUrl); taskManagementDetectionDetailVO.setVehiclePictures(jsonObject.toJSONString()); } taskManagementDetectionDetailVO.setVehiclePictures(vehiclePicture); taskManagementDetectionDetailVO.setTaskCode(task.getTaskCode()); XpVehicleDetection vehicleDetection = vehicleDetectionMapper.selectOne(new LambdaQueryWrapper<XpVehicleDetection>() xp-robotaxi-maintenance-boot/src/main/resources/i18n/messages.properties
@@ -2,4 +2,6 @@ welcome.message=欢迎来到我们的应用程序! task.not.exist=任务不存在 vehicle.not.exist=车辆不存在 repair.money.too.long=维修费用不能超过10字符 repair.money.too.long=维修费用不能超过10字符 task.save.error=获取车辆实时定位信息失败,请稍后重试 task.vehicle.not.exist=上报失败,未获取到车辆信息 xp-robotaxi-maintenance-boot/src/main/resources/i18n/messages_en_US.properties
@@ -3,4 +3,5 @@ task.not.exist=The task does not exist. vehicle.not.exist=The vehicle does not exist. repair.money.too.long=The maintenance cost cannot exceed 10 characters task.save.error=Failed to obtain the real-time positioning information of the vehicle. Please try again later task.rule.not.config=The vehicle accident task allocation rules have not been configured xp-robotaxi-maintenance-boot/src/main/resources/i18n/messages_zh_CN.properties
@@ -3,4 +3,6 @@ task.not.exist=任务不存在 vehicle.not.exist=车辆不存在 repair.money.too.long=维修费用不能超过10字符 task.save.error=获取车辆实时定位信息失败,请稍后重试 task.vehicle.not.exist=上报失败,未获取到车辆信息 task.rule.not.config=未配置车辆事故任务分配规则 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
@@ -453,15 +453,11 @@ throw new ServiceException("当前点位未开通服务", I18nKeyConstant.NO_CURRENT_REGION); } // 判断当天取消的次数 后台配置 redis 查询 Object cancelOrder = redisService.getCacheObject("CANCEL_ORDER_" + uid); // 静默处理 boolean isSilent = false; if (cancelOrder != null) { Integer num = Integer.valueOf(cancelOrder.toString()); if (num >= cancelCount) { isSilent = true; } Integer num = xpOrderClient.todayCancellationCount(Long.valueOf(uid)).getData(); if (num >= cancelCount) { isSilent = true; } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java
@@ -307,7 +307,6 @@ // 找出符合条件的 availableVehiclesNearby = availableVehiclesNearby.stream().filter(e -> data.contains(e.getVin())).collect(Collectors.toList()); // List<VehiclePositionVo> availableVehiclesNearby =vehiclePositionVos.getData(); if (!availableVehiclesNearby.isEmpty()) { xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpCruiseOrderController.java
@@ -170,6 +170,7 @@ // 2. 转换为导出对象 List<XpCruiseOrderExportExcel> exportList = BeanUtil.copyToList(dataList, XpCruiseOrderExportExcel.class); exportList.forEach(item -> item.setOrderSource("系统自动创建")); // 3. 生成 Excel Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), XpCruiseOrderExportExcel.class, exportList); xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
@@ -6,6 +6,7 @@ import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xiaopeng.api.dto.QueryOrderRouteDTO; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.order.AddCruiseMissionDto; @@ -584,4 +585,19 @@ return R.ok(routeVo); } /** * 当日取消订单次数 * * @param * @return 订单数量 */ @PostMapping("/inner/order/todayCancellationCount") public R<Integer> todayCancellationCount(@RequestParam Long userId){ long count = xpOrderService.count(new QueryWrapper<XpOrder>().eq("app_user_id", userId).eq("status", 0) .eq("is_deleted", 0).last(" and DATE_FORMAT(create_time, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d')")); return R.ok((int)count); } } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpTestOrderController.java
@@ -75,8 +75,7 @@ public class XpTestOrderController { private final IXpTestOrderService xpTestOrderService; @Autowired private XpVehicleClient xpVehicleClient; private final XpVehicleClient xpVehicleClient; /** @@ -107,6 +106,18 @@ } /** * 根据订单ID查询取消订单 * * @param orderId * @return */ @PostMapping("/inner/testOrder/cancelTestOrderById") public R<?> cancelTestOrderById(@RequestParam Long orderId) { return xpTestOrderService.cancelTestOrderById(orderId); } /** * 生成订单 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/exportExcel/XpCruiseOrderExportExcel.java
@@ -22,6 +22,9 @@ @Excel(name = "下单时间", width = 20, exportFormat = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; @Excel(name = "订单来源", width = 25) private String orderSource; @Excel(name = "起点", width = 30) private String startPointName; xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpTestOrderService.java
@@ -24,6 +24,7 @@ import com.xiaopeng.order.model.vo.*; import com.xiaopeng.order.vo.OrderDetailVo; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import java.math.BigDecimal; import java.util.List; @@ -121,4 +122,12 @@ * @param amount */ void changeAmount(Long id, BigDecimal amount); /** * 取消订单 * @param orderId * @return */ R<?> cancelTestOrderById(Long orderId); } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -941,23 +941,6 @@ } XpVehicle newVehicle = vehicleResult.getData().get(0); // 5. 校验新车辆的运营状态 // 车辆状态:1=待完善 2=待运营 3=保险/年检过期 // 运营状态:1=运营中 2=维修中 3=已收车 4=车辆异常 // 当前模式:1=接单 2=测试 // 模式状态:1=开始接单/开始测试 2=停止接单/停止测试 if (Objects.isNull(newVehicle.getStatus()) || newVehicle.getStatus() == 3) { throw new ServiceException("新车辆保险或年检已过期,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_STATUS_INVALID); } if (Objects.isNull(newVehicle.getOperatingStatus()) || newVehicle.getOperatingStatus() != 1) { throw new ServiceException("新车辆运营状态异常,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_OPERATING_STATUS_INVALID); } if (Objects.isNull(newVehicle.getAcceptOrTest()) || newVehicle.getAcceptOrTest() != 1) { throw new ServiceException("新车辆当前不在接单模式", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_IN_ACCEPT_MODE); } if (Objects.isNull(newVehicle.getAcceptOrTestStatus()) || newVehicle.getAcceptOrTestStatus() != 1) { throw new ServiceException("新车辆未开始接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_START_ACCEPT); } if (Objects.isNull(newVehicle.getState()) || newVehicle.getState() != 0) { throw new ServiceException("新车辆已接单,请重新选择", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_FREE); } @@ -1417,15 +1400,6 @@ xpOrderCancelService.save(xpOrderCancel); // 设置当天的取消次数缓存 Object cacheObject = redisService.getCacheObject("CANCEL_ORDER_" + uid); if (cacheObject == null) { redisService.setCacheCancelOrder("CANCEL_ORDER_" + uid, 1); } else { Integer i = Integer.valueOf(cacheObject.toString()); redisService.setCacheCancelOrder("CANCEL_ORDER_" + uid, i + 1); } // 移除mongo数据 xpPricingClient.deleteXpGeoQueryEntity(order.getId().toString()); @@ -1531,14 +1505,6 @@ // 移除mongo数据 xpPricingClient.deleteXpGeoQueryEntity(order.getId().toString()); // 设置当天的取消次数缓存 Object cacheObject = redisService.getCacheObject("CANCEL_ORDER_" + appUserId); if (cacheObject == null) { redisService.setCacheCancelOrder("CANCEL_ORDER_" + appUserId, 1); } else { Integer i = Integer.valueOf(cacheObject.toString()); redisService.setCacheCancelOrder("CANCEL_ORDER_" + appUserId, i + 1); } return order; } @@ -2666,7 +2632,7 @@ public void saveVehicleLocation(OrderTrajectory orderTrajectory) { // 查询订单信息 Integer status = redisService.getCacheObject("ORDER_STATUS:" + orderTrajectory.getOrderId()); if(status < 6){ if(status < 6 || status > 8){ return; } @@ -3008,7 +2974,7 @@ xpVehicleClient.updateVehicleById(vehicle1); log.info("推单成功后的处理逻辑,车辆状态修改1 {}", vehicle.getPlateNumber()); xpTestOrder.setVehicleId(null); xpTestOrder.setStartTestPointId(null); xpTestOrderService.updateById(xpTestOrder); redisService.setCacheObject("ORDER_STATUS:" + xpTestOrder.getId(), 2, 24L, TimeUnit.HOURS); } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpTestOrderServiceImpl.java
@@ -2,7 +2,6 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; @@ -11,20 +10,11 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.collect.ImmutableMap; import com.xiaopeng.api.dto.account.GetUserCouponDto; import com.xiaopeng.api.dto.account.UcUserInfo; import com.xiaopeng.api.dto.account.UseUserCouponDto; import com.xiaopeng.api.dto.automaticPilot.PushOrderDto; import com.xiaopeng.api.dto.map.RouteAndFareDto; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.order.GetOrderNumDto; import com.xiaopeng.api.dto.order.HistoryEndPointsDto; import com.xiaopeng.api.dto.order.HistoryStartPointsDto; import com.xiaopeng.api.dto.order.PopOrderDto; import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; import com.xiaopeng.api.dto.statistics.DailyCountDTO; import com.xiaopeng.api.dto.statistics.OrderStatisticsDTO; import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO; import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; import com.xiaopeng.api.feignClient.account.UserResourcesClient; import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient; import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient; @@ -36,7 +26,7 @@ import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.maintenance.XpTaskRule; import com.xiaopeng.api.model.map.XpTestPoint; import com.xiaopeng.api.model.operation.*; import com.xiaopeng.api.model.order.*; import com.xiaopeng.api.model.vehicleConvoy.XpFleet; @@ -45,18 +35,14 @@ import com.xiaopeng.api.vo.SystemEventType; import com.xiaopeng.api.vo.account.UserCouponVo; import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; import com.xiaopeng.api.vo.operation.FareVo; import com.xiaopeng.api.vo.operation.RouteAndFareVo; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.api.vo.order.*; import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo; import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo; import com.xiaopeng.api.vo.order.FareBreakdownDetailVo; import com.xiaopeng.api.vo.order.XpPricingCardVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.constant.Constants; import com.xiaopeng.common.core.constant.HttpStatus; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.OrderStatusEnum; import com.xiaopeng.common.core.enums.PushMessageTypeEnum; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.utils.DateUtils; import com.xiaopeng.common.core.utils.GeodesyUtil; @@ -66,36 +52,32 @@ import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.common.security.utils.SecurityUtils; import com.xiaopeng.order.constant.I18nKeyConstant; import com.xiaopeng.order.dto.MileageDto; import com.xiaopeng.order.job.base.QuartzManager; import com.xiaopeng.order.job.base.TimeJobType; import com.xiaopeng.order.job.jobs.AddCruiseMissionJob; import com.xiaopeng.order.job.jobs.EndTripJob; import com.xiaopeng.order.job.jobs.OrderCancelJob; import com.xiaopeng.order.mangodb.model.OrderTrajectory; import com.xiaopeng.order.mangodb.service.OrderTrajectoryService; import com.xiaopeng.order.mapper.*; import com.xiaopeng.order.model.dto.XpOrderCommentDto; import com.xiaopeng.order.model.dto.XpOrderPayDto; import com.xiaopeng.order.model.query.XpHistoryOrderListQuery; import com.xiaopeng.order.model.query.XpOrderExcelQuery; import com.xiaopeng.order.model.query.XpOrderPageQuery; import com.xiaopeng.order.mapper.XpCruiseOrderMapper; import com.xiaopeng.order.mapper.XpTestOrderDetailMapper; import com.xiaopeng.order.mapper.XpTestOrderMapper; import com.xiaopeng.order.model.query.XpTestOrderPageQuery; import com.xiaopeng.order.model.vo.*; import com.xiaopeng.order.service.*; import com.xiaopeng.order.model.vo.AddTestOrderVo; import com.xiaopeng.order.model.vo.XpTestOrderDetailVO; import com.xiaopeng.order.model.vo.XpTestOrderPageVO; import com.xiaopeng.order.service.IXpOrderEvaluateService; import com.xiaopeng.order.service.IXpOrderReassignService; import com.xiaopeng.order.service.IXpTestOrderCancelService; import com.xiaopeng.order.service.IXpTestOrderService; import com.xiaopeng.order.utils.GDMapGeocodingUtil; import com.xiaopeng.order.utils.RegionCodeFilterUtil; import com.xiaopeng.order.utils.TaxiPricingDemoService; import com.xiaopeng.order.utils.XpPricingUtil; import com.xiaopeng.order.utils.holiday.HolidayUtil; import com.xiaopeng.order.vo.OrderDetailVo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType; import org.apache.shardingsphere.transaction.core.TransactionType; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; @@ -106,13 +88,12 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.time.*; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneOffset; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -289,18 +270,10 @@ pushOrderDto.setStartLongitude(xpOrder.getStartLon()); pushOrderDto.setEndLatitude(xpOrder.getEndLat()); pushOrderDto.setEndLongitude(xpOrder.getEndLon()); pushOrderDto.setOrderType(OrderType.USER_ORDER); pushOrderDto.setOrderType(xpOrder.getOrderType() == 1 ? OrderType.TEST_ORDER : OrderType.TEST_CRUISE_ORDER); pushOrderDto.setStage(1); // 调用推送服务 orderId + carVin orderMissionClient.pushOrder(pushOrderDto); JSONObject jsonObject = new JSONObject(); jsonObject.put("event", SystemEventType.CREATE_ORDER); jsonObject.put("orderType", OrderType.TEST_ORDER); jsonObject.put("orderId", xpOrder.getId()); jsonObject.put("vin", xpVehicle.getVehicleVin()); redisService.setCacheObject("CREATE_ORDER:" + pushOrderDto.getOrderId(), jsonObject.toJSONString(),30L, TimeUnit.MINUTES); log.info("开始推送 {} 订单到XPU。", xpOrder.getOrderNumber()); } } @@ -654,14 +627,11 @@ // 下发命令 PushOrderDto pushOrderDto = new PushOrderDto(); pushOrderDto.setOrderId(order.getId().toString()); pushOrderDto.setOrderId("TEST" + order.getId().toString()); pushOrderDto.setVin(xpVehicle.getVehicleVin()); pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER); orderMissionClient.cancelOrder(pushOrderDto); log.info("运营人员取消订单成功,开始执行巡游订单 {}", order.getId()); //车辆继续巡游 addCruiseMission(xpVehicle.getId()); } else { log.info("查询车辆信息失败,订单ID: {}, 下发取消订单命令失败", order.getId()); } @@ -692,34 +662,19 @@ order.setMileageKilometers(new BigDecimal(reduce).divide(new BigDecimal(1000)).setScale(4, RoundingMode.HALF_EVEN).doubleValue()); long duration = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - order.getTripBegin().toEpochSecond(ZoneOffset.of("+8")); order.setDuration(new BigDecimal(duration).divide(new BigDecimal(60), 2, RoundingMode.HALF_EVEN).doubleValue()); order.setVehicleId(null); order.setStartTestPointId(null); this.updateById(order); redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 7, 24L, TimeUnit.HOURS); //给XPU推送订单取消的报文 PushOrderDto pushOrderDto = new PushOrderDto(); pushOrderDto.setOrderId(order.getId().toString()); pushOrderDto.setOrderId("TEST" + order.getId().toString()); pushOrderDto.setVin(xpVehicle.getVehicleVin()); pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER); orderMissionClient.cancelOrder(pushOrderDto); //结束行程,修改状态和计算费用 endTrip(order.getId()); //创建定时任务执行延迟驶离终点和下发巡游单 XpTestPoint point = xpTestPointClient.queryById(order.getEndTestPointId()).getData(); Map<String, ? extends Object> jobMaps = new ImmutableMap.Builder<String, String>() .put("id", order.getId().toString()) .put("appid", appid) .build(); QuartzManager.addJob( AddCruiseMissionJob.class, (AddCruiseMissionJob.name + order.getId()).toUpperCase(), TimeJobType.ADD_CRUISE_MISSION, DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())), jobMaps ); } /** @@ -787,7 +742,7 @@ // 6.1.1 取消原订单指令 PushOrderDto cancelDto = new PushOrderDto(); cancelDto.setOrderId(order.getId().toString()); cancelDto.setOrderId("TEST" + order.getId().toString()); cancelDto.setVin(oldVehicle.getVehicleVin()); cancelDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER); orderMissionClient.cancelOrder(cancelDto); @@ -843,6 +798,7 @@ if (Objects.nonNull(newFleetId)) { order.setFleetId(newFleetId); } order.setStartTestPointId(null); this.updateById(order); // 10. 保存改派记录 @@ -868,7 +824,7 @@ // 11.2 下发订单到新车辆 PushOrderDto pushOrderDto = new PushOrderDto(); pushOrderDto.setVin(newVehicle.getVehicleVin()); pushOrderDto.setOrderId(order.getId().toString()); pushOrderDto.setOrderId("TEST" + order.getId()); pushOrderDto.setStartLatitude(order.getStartLat()); pushOrderDto.setStartLongitude(order.getStartLon()); pushOrderDto.setEndLatitude(order.getEndLat()); @@ -968,48 +924,17 @@ xpOrder.setMileageKilometers(new BigDecimal(reduce).divide(new BigDecimal(1000)).setScale(4, RoundingMode.HALF_EVEN).doubleValue()); long duration = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - xpOrder.getTripBegin().toEpochSecond(ZoneOffset.of("+8")); xpOrder.setDuration(new BigDecimal(duration).divide(new BigDecimal(60), 2, RoundingMode.HALF_EVEN).doubleValue()); //创建定时结束订单和等待结束后下发巡游单的定时任务 Integer arriveTime = xpSystemSettingClient.getOrderFinishTime().getData(); // 添加自动结束行程定时任务job Map<String, ? extends Object> endTripJobMaps = new ImmutableMap.Builder<String, String>() .put("id", xpOrder.getId().toString()) .put("appid", appid) .build(); QuartzManager.addJob( EndTripJob.class, (EndTripJob.name + xpOrder.getId()).toUpperCase(), TimeJobType.END_TRIP, DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(arriveTime)), endTripJobMaps ); // 添加车辆到达终点后限停时间到后驶离的定时任务 //时间到后将车辆状态回滚到空闲、添加巡游订单,解绑用户和车辆关系,车辆驶离点位 XpTestPoint point = xpTestPointClient.queryById(xpOrder.getEndTestPointId()).getData(); Map<String, ? extends Object> jobMaps = new ImmutableMap.Builder<String, String>() .put("id", xpOrder.getId().toString()) .put("appid", appid) .build(); QuartzManager.addJob( AddCruiseMissionJob.class, (AddCruiseMissionJob.name + xpOrder.getId()).toUpperCase(), TimeJobType.ADD_CRUISE_MISSION, DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())), jobMaps ); break; } xpOrder.setStatus(status); xpOrder.setVehicleId(null); xpOrder.setStartTestPointId(null); this.updateById(xpOrder); redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), status, 24L, TimeUnit.HOURS); }else{ if(status == 10){ xpOrder.setStatus(status); xpOrder.setVehicleId(null); xpOrder.setStartTestPointId(null); this.updateById(xpOrder); redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), status, 24L, TimeUnit.HOURS); } @@ -1037,7 +962,7 @@ throw new RuntimeException("订单状态错误"); } order.setStatus(8); order.setVehicleId(null); order.setStartTestPointId(null); order.setTripEnd(LocalDateTime.now()); baseMapper.updateById(order); redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 8, 24L, TimeUnit.HOURS); @@ -1079,7 +1004,7 @@ JSONObject basicPricingJson = JSONObject.parseObject(pricing.getBasicPricingJson()); XpPricingCardVo xpPricingCardVo = xpPricingUtil.calculationFixedPrice(uid, basicPricingJson, null, mileageKilometers, duration1, 0, 0.0, pricing.getIsDynamicPrice(), order.getCityId(), pricing.getDynamicPricingJson()); XpPricingCardVo xpPricingCardVo = xpPricingUtil.calculationFixedPrice(order.getVehicleId().toString(), basicPricingJson, null, mileageKilometers, duration1, 0, 0.0, pricing.getIsDynamicPrice(), order.getCityId(), pricing.getDynamicPricingJson()); XpTestOrderDetail xpOrderDetail = new XpTestOrderDetail(); xpOrderDetail.setDetailType(1); xpOrderDetail.setOrderId(orderId); @@ -1109,7 +1034,7 @@ xpTestOrderDetailMapper.insert(xpOrderDetail1); } order.setOrderMoney(totalPrice); order.setVehicleId(null); order.setStartTestPointId(null); baseMapper.updateById(order); } else { //动态计费 @@ -1174,7 +1099,7 @@ double priceRate = 1; if (pricing.getIsDynamicPrice() == 1) { // 先判断是否已经调价过了 Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + order.getCityId() + "_" + uid); Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + order.getCityId() + "_" + order.getVehicleId()); if (userDynamicPriceObj != null) { // 是否调价过了 priceRate = Double.parseDouble(userDynamicPriceObj.toString()); @@ -1204,7 +1129,7 @@ // 冷却时间 Integer time = getOrderNum(jsonObject, 6); // 触发调价了 redisService.setCacheObject("USER_DYNAMIC_PRICE_" + order.getCityId() + "_" + uid, priceRate, time.longValue(), TimeUnit.MINUTES); redisService.setCacheObject("USER_DYNAMIC_PRICE_" + order.getCityId() + "_" + order.getVehicleId(), priceRate, time.longValue(), TimeUnit.MINUTES); } } @@ -1367,41 +1292,13 @@ .add(order.getLongDistancemoney() != null ? order.getLongDistancemoney() : BigDecimal.ZERO) .add(order.getWaitMoney() != null ? order.getWaitMoney() : BigDecimal.ZERO); order.setOrderMoney(orderMoney); order.setVehicleId(null); order.setStartTestPointId(null); baseMapper.updateById(order); } // 计算完价格后 挑选优惠券 GetUserCouponDto getUserCouponDto = new GetUserCouponDto(); getUserCouponDto.setUserId(Long.valueOf(uid)); getUserCouponDto.setTotalAmount(order.getOrderMoney().doubleValue()); getUserCouponDto.setUserCouponId(order.getCouponId()); getUserCouponDto.setOpenCityId(order.getCityId()); R<UserCouponVo> userCouponVoR = xpAppUserCouponClient.getUserCoupon(getUserCouponDto); UserCouponVo userCouponVo = userCouponVoR.getData(); // 提示是否换券 boolean tip =false; if (userCouponVo != null) { // 重新选券 if(userCouponVo.getStatus()==2){ getUserCouponDto.setUserId(Long.valueOf(uid)); getUserCouponDto.setTotalAmount(order.getOrderMoney().doubleValue()); getUserCouponDto.setUserCouponId(order.getCouponId()); getUserCouponDto.setOpenCityId(order.getCityId()); userCouponVoR = xpAppUserCouponClient.getUserCoupon(getUserCouponDto); userCouponVo = userCouponVoR.getData(); tip=true; } order.setCouponId(userCouponVo.getId()); order.setCouponMoney(BigDecimal.valueOf(userCouponVo.getMoney())); } order.setVehicleId(null); order.setStartTestPointId(null); baseMapper.updateById(order); return tip; return true; } @@ -1437,7 +1334,7 @@ public void saveVehicleLocation(OrderTrajectory orderTrajectory) { // 查询订单信息 Integer status = redisService.getCacheObject("ORDER_STATUS:" + orderTrajectory.getOrderId()); if(status < 6){ if(status < 6 || status > 8){ return; } @@ -1545,66 +1442,6 @@ /** * 发送乘客导航路径数据 * * @param appUserId * @param keyStr */ public void sendRoute(String appUserId, Long orderId, String keyStr, String vin) { VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class); Object cacheObject = redisService.getCacheObject(keyStr + ":" + appUserId); if (null != cacheObject) { RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class); JSONObject jsonObject = new JSONObject(); jsonObject.put("type", "ORDER_ROUTE"); jsonObject.put("timestamp", System.currentTimeMillis()); JSONObject content = new JSONObject(); content.put("orderId", orderId.toString()); content.put("routeType", "ORDER_NAVIGATION_START_DATA".equals(keyStr) ? 1 : 2); content.put("direction", null != vehiclePosition ? vehiclePosition.getCourse() : 90); JSONObject route = new JSONObject(); route.put("distance", routeVo.getDistance()); route.put("duration", routeVo.getDuration()); route.put("routeID", routeVo.getRouteID()); List<JSONObject> collect = routeVo.getPolyline().stream().map(item -> { JSONObject point = new JSONObject(); point.put("latitude", item.getLatitude()); point.put("longitude", item.getLongitude()); return point; }).collect(Collectors.toList()); route.put("polyline", JSON.toJSONString(collect)); content.put("route", route.toJSONString()); jsonObject.put("content", content.toJSONString()); SendMessageDTO messageDTO = new SendMessageDTO(); messageDTO.setAppUserId(appUserId); messageDTO.setMessage(jsonObject.toJSONString()); R<String> stringR = xpPushMessageClient.sendRoute(messageDTO); XpTestOrder xpOrder = this.getById(orderId); //推送失败,重试3次 if(stringR.getCode() != Constants.SUCCESS){ ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); executor.execute(() -> { for (int i = 0; i < 3; i++) { R<String> stringR1 = xpPushMessageClient.sendStatus(messageDTO); if(stringR1.getCode() == Constants.SUCCESS){ break; } try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } log.info("推送乘客端导航数据消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(messageDTO), xpOrder.getOrderNumber()); } }); } } } @Override public void changeAmount(Long id, BigDecimal amount) { @@ -1643,4 +1480,26 @@ throw new ServiceException("订单改价失败,请稍后重试", I18nKeyConstant.ORDER_CHANGE_AMOUNT_FAILED); } } @Override public R<?> cancelTestOrderById(Long orderId) { XpTestOrder xpTestOrder = this.getById(orderId); if (xpTestOrder != null) { xpTestOrder.setStatus(0); xpTestOrder.setStartTestPointId(null); this.updateById(xpTestOrder); XpVehicle xpVehicle = xpVehicleClient.queryById(xpTestOrder.getVehicleId()).getData(); PushOrderDto pushOrderDto = new PushOrderDto(); pushOrderDto.setVin(xpVehicle.getVehicleVin()); pushOrderDto.setOrderId("TEST" + xpTestOrder.getId()); pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER); R<Boolean> booleanR = orderMissionClient.cancelOrder(pushOrderDto); if(booleanR==null || !booleanR.getData()){ log.error("XPU取消测试巡游订单失败"); return R.fail("XPU取消测试巡游订单失败"); } return R.ok(); } return R.fail("获取订单失败"); } } xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -763,7 +763,8 @@ */ @PostMapping("/inner/vehicle/queryVehiclePositionByVin") public R<List<String>> queryVehiclePositionByVin(@RequestBody VehiclePositionByVinDto dto){ List<XpVehicle> list = xpVehicleService.list(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, 0).eq(XpVehicle::getOperatingStatus, 1).eq(XpVehicle::getElectronicId, dto.getFenceId()).in(XpVehicle::getVehicleVin, List<XpVehicle> list = xpVehicleService.list(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, 0) .eq(XpVehicle::getOperatingStatus, 1).eq(XpVehicle::getElectronicId, dto.getFenceId()).in(XpVehicle::getVehicleVin, dto.getVinList())); if(list.isEmpty()){ return R.ok(new ArrayList<>()); xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -299,13 +299,17 @@ if (gearLevel == null || gearLevel != 4) { throw new ServiceException("车辆非P档,无法操作后备箱", I18nKeyConstant.VEHICLE_NOT_P_GEAR); } if(xpOrder.getOpenTrunk()==0){ xpOrder.setOpenTrunk(1); vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_OPEN.getCommand()); } 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); vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_CLOSE.getCommand()); }else{ //关闭状态 xpOrder.setOpenTrunk(1); vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_OPEN.getCommand()); } } try { @@ -319,9 +323,7 @@ //} String result = vehicleControlUtil.vehiclesCommand(vehiclesCommandVo, xpOrder.getAppUserId()); log.info("车辆控制结果:{}", result); JSONObject jsonObject = JSONObject.parseObject(result); String msgId = jsonObject.getString("msgId"); if (StringUtils.isEmpty(msgId)) { if (!result.contains("msgId")) { return 0; }else { xpOrderClient.updateOrder(xpOrder); @@ -359,16 +361,14 @@ vehiclesCommandVo.setExtParam(vehiclesCommandParamVo); try { String result = vehicleControlUtil.vehiclesCommand(vehiclesCommandVo, xpOrder.getAppUserId()); log.info("车辆控制结果:{}", result); JSONObject jsonObject = JSONObject.parseObject(result); String msgId = jsonObject.getString("msgId"); if (StringUtils.isEmpty(msgId)) { 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; } }