| | |
| | | package com.xiaopeng.operation.utils; |
| | | |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.alibaba.fastjson2.JSON; |
| | | 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.operation.VehiclePositionByVinDto; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; |
| | | import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient; |
| | | import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient; |
| | | import com.xiaopeng.api.feignClient.map.XpMapClient; |
| | | import com.xiaopeng.api.feignClient.operation.XpTradingStrategyClient; |
| | | import com.xiaopeng.api.feignClient.order.XpCruiseOrderClient; |
| | | import com.xiaopeng.api.feignClient.order.XpOrderClient; |
| | | import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.operation.XpElectronicFence; |
| | | import com.xiaopeng.api.model.operation.XpTradingStrategy; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.api.model.order.XpOrderReassign; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.OrderType; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.operation.RouteVo; |
| | | import com.xiaopeng.api.vo.operation.VehiclePositionVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo; |
| | | import com.xiaopeng.api.vo.operation.XpTradingStrategyDetailVO; |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | | import com.xiaopeng.common.core.constant.Constants; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.OrderStatusEnum; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.operation.config.UidVinBindingConfig; |
| | | import com.xiaopeng.operation.dto.PriorityMatchResult; |
| | | import com.xiaopeng.operation.mapper.XpElectronicFenceMapper; |
| | | import com.xiaopeng.operation.service.IXpElectronicFenceAreaService; |
| | | import com.xiaopeng.operation.service.IXpTradingStrategyService; |
| | | import com.xiaopeng.operation.service.UidVinPriorityMatcher; |
| | | import com.xiaopeng.operation.service.XpPointService; |
| | | import com.xiaopeng.operation.utils.mango.VehiclePositionService; |
| | | import lombok.SneakyThrows; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.redisson.api.RLock; |
| | | import org.redisson.api.RedissonClient; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.mongodb.core.MongoTemplate; |
| | | import org.springframework.data.mongodb.core.query.Criteria; |
| | | import org.springframework.data.mongodb.core.query.Query; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | | import java.util.concurrent.LinkedBlockingQueue; |
| | | import java.util.concurrent.ThreadPoolExecutor; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | private XpCruiseOrderClient xpCruiseOrderClient; |
| | | |
| | | @Resource |
| | | private XpTradingStrategyClient tradingStrategyClient; |
| | | |
| | | @Resource |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Resource |
| | |
| | | @Resource |
| | | private XpElectronicFenceMapper xpElectronicFenceMapper; |
| | | |
| | | @Resource |
| | | private UidVinBindingConfig uidVinBindingConfig; |
| | | |
| | | @Resource |
| | | private UidVinPriorityMatcher uidVinPriorityMatcher; |
| | | @Resource |
| | | private XpAppUserCouponClient xpAppUserCouponClient; |
| | | |
| | | |
| | | // 自定义线程池 |
| | | private static final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); |
| | | |
| | | // ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(20); |
| | | |
| | | static { |
| | | threadPoolTaskExecutor.setCorePoolSize(20); |
| | |
| | | * @param firstElement 队列第一个元素 |
| | | */ |
| | | private void orderProcess(String quoteName, String firstElement) { |
| | | System.out.println("进入处理环节"); |
| | | XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null); |
| | | String orderId = firstElement.split("_")[0]; |
| | | String lonLat = firstElement.split("_")[1]; |
| | |
| | | if (xpOrderR.getCode() == 200) { |
| | | XpOrder xpOrder = xpOrderR.getData(); |
| | | if (xpOrder.getStatus() == 1) { |
| | | log.error("五轮推单结束,无车辆接单,执行取消订单 {}", orderNo); |
| | | log.info("五轮推单结束,无车辆接单,执行取消订单 {}", orderNo); |
| | | xpOrderClient.cancelOrder(orderId); |
| | | //推送订单状态给乘客 |
| | | SendMessageDTO dto = new SendMessageDTO(); |
| | | dto.setAppUserId(xpOrder.getAppUserId().toString()); |
| | | dto.setMessage("{\"type\":\"ORDER_STATUS\",\"content\":\"{\\\"orderId\\\":\\\"" + orderId + "\\\",\\\"status\\\":0}\",\"timestamp\":\"" + System.currentTimeMillis() + "\"}"); |
| | | xpPushMessageClient.sendStatus(dto); |
| | | R<String> stringR = xpPushMessageClient.sendStatus(dto); |
| | | //推送失败,重试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(dto); |
| | | if(stringR1.getCode() == Constants.SUCCESS){ |
| | | break; |
| | | } |
| | | try { |
| | | Thread.sleep(1000); |
| | | } catch (InterruptedException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | log.info("五轮推单结束后,无车辆接单,推送取消消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(dto), xpOrder.getOrderNumber()); |
| | | } |
| | | }); |
| | | } |
| | | //将订单从队列中移除 |
| | | log.info("五轮推单结束,无车辆接单,执行队列移除订单 {}", orderNo); |
| | | redisService.popFirstElement(quoteName); |
| | |
| | | Long electronicId = xpElectronicFenceAreaService.getById(xpElectronicFenceAreaId).getElectronicId(); |
| | | XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(electronicId); |
| | | |
| | | // ===== 新增:UID-VIN 优先匹配(仅 enabled=true 时生效)===== |
| | | log.info("[人车订单绑定测试] >>>>>> 进入优先匹配判断, uid={}, orderNo={}, 围栏区域ID={}", uid, orderNo, xpElectronicFenceAreaId); |
| | | if (uidVinBindingConfig.isEnabled()) { |
| | | log.info("[人车订单绑定测试] 总开关已开启, 开始执行优先匹配逻辑, uid={}, orderNo={}", uid, orderNo); |
| | | try { |
| | | PriorityMatchResult priorityResult = uidVinPriorityMatcher.tryPriorityMatch(uid, orderNo, String.valueOf(xpElectronicFenceAreaId)); |
| | | log.info("[人车订单绑定测试] 优先匹配结果: matched={}, vin={}, failReason={}, uid={}, orderNo={}", |
| | | priorityResult != null ? priorityResult.isMatched() : "null", |
| | | priorityResult != null ? priorityResult.getVin() : "null", |
| | | priorityResult != null ? priorityResult.getFailReason() : "null", |
| | | uid, orderNo); |
| | | if (priorityResult != null && priorityResult.isMatched()) { |
| | | String priorityVin = priorityResult.getVin(); |
| | | log.info("[人车订单绑定测试] 匹配成功, 准备获取分布式锁, lockKey=FIND_CAR_{}, orderNo={}", priorityVin, orderNo); |
| | | RLock priorityLock = redissonClient.getLock("FIND_CAR_" + priorityVin); |
| | | priorityLock.lock(10, TimeUnit.SECONDS); |
| | | log.info("[人车订单绑定测试] 分布式锁获取成功, vin={}, orderNo={}", priorityVin, orderNo); |
| | | try { |
| | | // 二次校验车辆状态 |
| | | log.info("[人车订单绑定测试] 开始二次校验车辆状态, vin={}, orderNo={}", priorityVin, orderNo); |
| | | R<XpVehicle> vehicleR = xpVehicleClient.findByVehicleVin(priorityVin); |
| | | log.info("[人车订单绑定测试] 二次校验-车辆查询结果: code={}, hasData={}, vin={}", vehicleR.getCode(), vehicleR.getData() != null, priorityVin); |
| | | if (vehicleR.getCode() == 200 && vehicleR.getData() != null) { |
| | | XpVehicle vehicle = vehicleR.getData(); |
| | | log.info("[人车订单绑定测试] 二次校验-车辆状态: operatingStatus={}, state={}, vehicleType={}, vin={}", |
| | | vehicle.getOperatingStatus(), vehicle.getState(), vehicle.getVehicleType(), priorityVin); |
| | | if (vehicle.getOperatingStatus() == 1 && vehicle.getState() == 0 && vehicle.getVehicleType() != 1) { |
| | | log.info("[人车订单绑定测试] 二次校验-车辆状态通过(空闲), 开始校验订单状态, orderNo={}", orderNo); |
| | | // 二次校验订单状态 |
| | | R<XpOrder> orderCheck = xpOrderClient.queryOrderByOrderNo(orderNo); |
| | | log.info("[人车订单绑定测试] 二次校验-订单查询结果: code={}, status={}, orderNo={}", |
| | | orderCheck.getCode(), |
| | | orderCheck.getData() != null ? orderCheck.getData().getStatus() : "null", |
| | | orderNo); |
| | | if (orderCheck.getCode() == 200 && orderCheck.getData() != null && orderCheck.getData().getStatus() == 1) { |
| | | log.info("[人车订单绑定测试] 二次校验全部通过, 开始关闭巡游单, vin={}, orderNo={}", priorityVin, orderNo); |
| | | // 关闭巡游单 |
| | | R stringR = xpCruiseOrderClient.cancelCruiseOrderByVin(priorityVin); |
| | | log.info("[人车订单绑定测试] 关闭巡游单结果: code={}, vin={}, orderNo={}", |
| | | stringR != null ? stringR.getCode() : "null", priorityVin, orderNo); |
| | | if (stringR != null && stringR.getCode() == 200) { |
| | | log.info("[人车订单绑定测试] 关闭巡游单成功, 开始下发XPU命令, vin={}, orderNo={}", priorityVin, orderNo); |
| | | // 下发XPU命令 |
| | | PushOrderDto pushOrderDto = new PushOrderDto(); |
| | | pushOrderDto.setVin(priorityVin); |
| | | pushOrderDto.setTaskId(orderCheck.getData().getXpuTaskId()); |
| | | pushOrderDto.setOrderId(orderCheck.getData().getId().toString()); |
| | | pushOrderDto.setStartLatitude(orderCheck.getData().getStartLat()); |
| | | pushOrderDto.setStartLongitude(orderCheck.getData().getStartLon()); |
| | | pushOrderDto.setEndLatitude(orderCheck.getData().getEndLat()); |
| | | pushOrderDto.setEndLongitude(orderCheck.getData().getEndLon()); |
| | | pushOrderDto.setEndPoiName(orderCheck.getData().getEndPointName()); |
| | | pushOrderDto.setOrderType(OrderType.USER_ORDER); |
| | | pushOrderDto.setStage(1); |
| | | log.info("[人车订单绑定测试] XPU推单参数: vin={}, orderId={}, startLat={}, startLon={}, endLat={}, endLon={}, orderNo={}", |
| | | priorityVin, orderCheck.getData().getId(), orderCheck.getData().getStartLat(), orderCheck.getData().getStartLon(), |
| | | orderCheck.getData().getEndLat(), orderCheck.getData().getEndLon(), orderNo); |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | log.info("[人车订单绑定测试] ====== 派单成功! uid={}, vin={}, orderNo={}, 从队列移除订单 ======", uid, priorityVin, orderNo); |
| | | redisService.removeByPattern(quoteName, orderNo); |
| | | return true; |
| | | } else { |
| | | log.info("[人车订单绑定测试] 关闭巡游单失败, 回退常规流程, vin={}, orderNo={}", priorityVin, orderNo); |
| | | } |
| | | } else { |
| | | log.info("[人车订单绑定测试] 二次校验-订单状态不满足(非待派单), 回退常规流程, orderNo={}", orderNo); |
| | | } |
| | | } else { |
| | | if (vehicle.getState() != 0) { |
| | | log.info("[人车订单绑定测试] 二次校验-车辆已接单(state={}), 当前有未完成订单, 无法指派, vin={}, plateNumber={}, orderNo={}", |
| | | vehicle.getState(), priorityVin, vehicle.getPlateNumber(), orderNo); |
| | | } else { |
| | | log.info("[人车订单绑定测试] 二次校验-车辆状态不满足, 回退常规流程, vin={}, operatingStatus={}, state={}, vehicleType={}", |
| | | priorityVin, vehicle.getOperatingStatus(), vehicle.getState(), vehicle.getVehicleType()); |
| | | } |
| | | } |
| | | } else { |
| | | log.info("[人车订单绑定测试] 二次校验-车辆查询失败, 回退常规流程, vin={}, code={}", priorityVin, vehicleR.getCode()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("[人车订单绑定测试] 锁内执行异常,回退常规流程, uid={}, vin={}, orderNo={}", uid, priorityVin, orderNo, e); |
| | | } finally { |
| | | priorityLock.unlock(); |
| | | log.info("[人车订单绑定测试] 分布式锁已释放, vin={}, orderNo={}", priorityVin, orderNo); |
| | | } |
| | | } else { |
| | | log.info("[人车订单绑定测试] 优先匹配未命中, 进入常规流程, uid={}, orderNo={}", uid, orderNo); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("[人车订单绑定测试] 优先匹配过程异常,回退常规流程, uid={}, orderNo={}", uid, orderNo, e); |
| | | } |
| | | } else { |
| | | log.info("[人车订单绑定测试] 总开关未开启(enabled=false), 跳过优先匹配, uid={}, orderNo={}", uid, orderNo); |
| | | } |
| | | // ===== 新增结束 ===== |
| | | |
| | | for (int i = 0; i < count; i++) { |
| | | //等到sleepTime秒钟 |
| | | Thread.sleep(sleepTime * 1000); |
| | |
| | | |
| | | // 找出符合条件的 |
| | | availableVehiclesNearby = availableVehiclesNearby.stream().filter(e -> data.contains(e.getVin())).collect(Collectors.toList()); |
| | | |
| | | // List<VehiclePositionVo> availableVehiclesNearby =vehiclePositionVos.getData(); |
| | | |
| | | if (!availableVehiclesNearby.isEmpty()) { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | // 距离差 |
| | | |
| | | if (max1.equals(weightDistanceDifference)) { |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | |
| | | } |
| | | |
| | | if (max1.equals(weightDistance)) { |
| | | log.info("车子距离~~"); |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | | LonLatDto lonLatDto = new LonLatDto(); |
| | |
| | | // 调用地图 获取时间 |
| | | R<RouteVo> r = xpMapClient.getDistanceAndDuration(routeAndFareDto); |
| | | if (r.getCode() == 200) { |
| | | log.info("车子距离~~{},{},{}",vehiclePosition.getVin(),r.getData().getDistance(),orderNo); |
| | | vehiclePosition.setDistance(Double.valueOf(r.getData().getDistance())); |
| | | } else { |
| | | vehiclePosition.setDistance(0.0); |
| | | } |
| | | |
| | | } |
| | | |
| | | // 分数计算 把时间短的分数调高 |
| | | availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getDistance)).collect(Collectors.toList()); |
| | | double score = 10; |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | vehiclePosition.setDistance(score); |
| | | score--; |
| | | } |
| | | |
| | | } |
| | | |
| | | if (max1.equals(weightTime)) { |
| | |
| | | vehiclePosition.setSecond(0); |
| | | } |
| | | } |
| | | // 分数计算 把时间短的分数调高 |
| | | availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getSecond)).collect(Collectors.toList()); |
| | | int score = 10; |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | vehiclePosition.setSecond(score); |
| | | score--; |
| | | } |
| | | |
| | | } |
| | | |
| | | if (max1.equals(weightElectricity)) { |
| | |
| | | |
| | | // 距离分数 |
| | | if (max.equals(tendencyDistance)) { |
| | | log.info("车子距离~~"); |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | | LonLatDto lonLatDto = new LonLatDto(); |
| | |
| | | // 调用地图 获取时间 |
| | | R<RouteVo> r = xpMapClient.getDistanceAndDuration(routeAndFareDto); |
| | | if (r.getCode() == 200) { |
| | | log.info("车子距离~~{},{},{}",vehiclePosition.getVin(),r.getData().getDistance(),orderNo); |
| | | vehiclePosition.setDistance(Double.valueOf(r.getData().getDistance())); |
| | | } else { |
| | | vehiclePosition.setDistance(0.0); |
| | | } |
| | | } |
| | | // availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getDistance)).collect(Collectors.toList()); |
| | | // int size = tendencyDistance; |
| | | // // 做比对的分数 |
| | | // double temp = availableVehiclesNearby.get(0).getDistance(); |
| | | // for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | // vehiclePosition.setDistanceScore(vehiclePosition.getDistanceScore() + size); |
| | | // if (temp != vehiclePosition.getDistance()) { |
| | | // size--; |
| | | // } |
| | | // } |
| | | |
| | | // 分数计算 把时间短的分数调高 |
| | | availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getDistance)).collect(Collectors.toList()); |
| | | int size = tendencyDistance; |
| | | // 做比对的分数 |
| | | double temp = availableVehiclesNearby.get(0).getDistance(); |
| | | int score = 10; |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | vehiclePosition.setDistanceScore(vehiclePosition.getDistanceScore() + size); |
| | | if (temp != vehiclePosition.getDistance()) { |
| | | size--; |
| | | } |
| | | vehiclePosition.setDistanceScore(score); |
| | | score--; |
| | | } |
| | | } |
| | | |
| | |
| | | vehiclePosition.setSecond(0); |
| | | } |
| | | } |
| | | |
| | | // 分数计算 把时间短的分数调高 |
| | | availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getSecond)).collect(Collectors.toList()); |
| | | int size = tendencyTime; |
| | | // 做比对的分数 |
| | | double temp = availableVehiclesNearby.get(0).getSecond(); |
| | | int score = 10; |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | vehiclePosition.setTimeScore(vehiclePosition.getTimeScore() + size); |
| | | if (temp != vehiclePosition.getSecond()) { |
| | | size--; |
| | | } |
| | | vehiclePosition.setTimeScore(score); |
| | | score--; |
| | | } |
| | | // availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getSecond)).collect(Collectors.toList()); |
| | | // int size = tendencyTime; |
| | | // // 做比对的分数 |
| | | // double temp = availableVehiclesNearby.get(0).getSecond(); |
| | | // for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | // vehiclePosition.setTimeScore(vehiclePosition.getTimeScore() + size); |
| | | // if (temp != vehiclePosition.getSecond()) { |
| | | // size--; |
| | | // } |
| | | // } |
| | | |
| | | } |
| | | |
| | |
| | | lock.lock(10, TimeUnit.SECONDS); |
| | | log.info("队列 {} 车辆 {} 单号 {}", quoteName, vehiclePositionVo.getVin(), orderNo); |
| | | try { |
| | | |
| | | |
| | | |
| | | // VehiclePosition vehiclePosition = vehiclePositionService.findByVehicleId(vehiclePositionVo.getVehicle_id()); |
| | | R<XpVehicle> vehiclePositionR = xpVehicleClient.findByVehicleVin(vehiclePositionVo.getVin()); |
| | | if (vehiclePositionR.getCode() != 200) { |
| | |
| | | if (vehiclePosition.getOperatingStatus() != 1 || vehiclePosition.getState() != 0 || vehiclePosition.getVehicleType() == 1) { |
| | | continue; |
| | | } |
| | | |
| | | // 再次查询一下订单 看是否取消 |
| | | xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo); |
| | | if (xpOrderR.getCode() != 200) { |
| | | continue; |
| | | } |
| | | xpOrder = xpOrderR.getData(); |
| | | if (xpOrder.getStatus() != 1) { |
| | | continue; |
| | | } |
| | | |
| | | |
| | | // 关闭巡游单子 |
| | | R<Long> stringR = xpCruiseOrderClient.updateCruiseOrder(vehiclePosition.getVehicleVin()); |
| | | R stringR = xpCruiseOrderClient.cancelCruiseOrderByVin(vehiclePosition.getVehicleVin()); |
| | | if (stringR == null || stringR.getCode() != 200) { |
| | | log.info("关闭巡游单子失败 车牌号 {}", vehiclePosition.getPlateNumber()); |
| | | continue; |
| | | } |
| | | |
| | | log.info("关闭巡游单成功 {} {}", vehiclePosition.getPlateNumber(), orderNo); |
| | | // 下发命令 |
| | | PushOrderDto pushOrderDto = new PushOrderDto(); |
| | | pushOrderDto.setTaskId(xpOrder.getXpuTaskId()); |
| | | pushOrderDto.setVin(vehiclePosition.getVehicleVin()); |
| | | pushOrderDto.setOrderId(xpOrder.getId().toString()); |
| | | pushOrderDto.setStartLatitude(xpOrder.getStartLat()); |
| | | pushOrderDto.setStartLongitude(xpOrder.getStartLon()); |
| | | pushOrderDto.setEndLatitude(xpOrder.getEndLat()); |
| | | pushOrderDto.setEndLongitude(xpOrder.getEndLon()); |
| | | pushOrderDto.setEndPoiName(xpOrder.getEndPointName()); |
| | | pushOrderDto.setOrderType(OrderType.USER_ORDER); |
| | | pushOrderDto.setStage(1); |
| | | // 调用推送服务 orderId + carVin |
| | |
| | | } |
| | | XpVehicle vehicleId1 = vehicleR.getData(); |
| | | log.info("附近只有一个车辆 {} ,直接推单XPU。单号 {}", vehicleId1.getPlateNumber(), orderNo); |
| | | log.info("当前车辆状态 {} 运营状态 {} 单号 {}", vehicleId1.getOperatingStatus(), vehicleId1.getState(), orderNo); |
| | | log.info("当前车辆状态 运营状态 {} 单号 {}", vehicleId1.getState(), orderNo); |
| | | if (vehicleId1.getOperatingStatus() != 1 || vehicleId1.getState() != 0 || vehicleId1.getVehicleType() == 1) { |
| | | continue; |
| | | } |
| | | |
| | | |
| | | // 再次查询一下订单 看是否取消 |
| | | xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo); |
| | | if (xpOrderR.getCode() != 200) { |
| | | continue; |
| | | } |
| | | xpOrder = xpOrderR.getData(); |
| | | if (xpOrder.getStatus() != 1) { |
| | | continue; |
| | | } |
| | | |
| | | // 关闭巡游单子 |
| | | R<Long> stringR = xpCruiseOrderClient.updateCruiseOrder(vehicleId1.getVehicleVin()); |
| | | R<?> stringR = xpCruiseOrderClient.cancelCruiseOrderByVin(vehicleId1.getVehicleVin()); |
| | | if (stringR == null || stringR.getCode() != 200) { |
| | | log.info("关闭巡游单子失败 车牌号 {}", vehicleId1.getPlateNumber()); |
| | | continue; |
| | | } |
| | | |
| | | PushOrderDto pushOrderDto = new PushOrderDto(); |
| | | log.info("关闭巡游单成功 {} {}", vehicleId1.getPlateNumber(), orderNo); |
| | | PushOrderDto pushOrderDto = buildPushOrderDto(xpOrder); |
| | | pushOrderDto.setVin(vehiclePosition.getVin()); |
| | | pushOrderDto.setOrderId(xpOrder.getId().toString()); |
| | | pushOrderDto.setStartLatitude(xpOrder.getStartLat()); |
| | | pushOrderDto.setStartLongitude(xpOrder.getStartLon()); |
| | | pushOrderDto.setEndLatitude(xpOrder.getEndLat()); |
| | | pushOrderDto.setEndLongitude(xpOrder.getEndLon()); |
| | | pushOrderDto.setOrderType(OrderType.USER_ORDER); |
| | | pushOrderDto.setStage(1); |
| | | pushOrderDto.setTaskId(xpOrder.getXpuTaskId()); |
| | | // 调用推送服务 orderId + carVin |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | log.info("开始推送 {} 订单到XPU", xpOrder.getOrderNumber()); |
| | |
| | | |
| | | } |
| | | } |
| | | |
| | | log.info("没有找到空闲车辆 {},尝试连环派单给即将服务结束的车辆", orderNo); |
| | | // 查询状态为1的车辆vin |
| | | R<List<String>> servingVehicles = xpVehicleClient.queryVehiclePositionByVin(new VehiclePositionByVinDto(xpElectronicFence.getId(), vinList, xpTradingStrategy.getSimultaneouslyOrderCount(),1)); |
| | | if (servingVehicles.getCode() != 200) { |
| | | continue; |
| | | } |
| | | |
| | | LonLatDto userPostion = new LonLatDto(Double.parseDouble(split[0]), Double.parseDouble(split[1])); |
| | | |
| | | XpTradingStrategyDetailVO strategyDetailVO = tradingStrategyClient.queryById().getData(); |
| | | |
| | | Integer distanceRegardAsEnding = strategyDetailVO.getDistanceRegardAsEnding(); |
| | | Integer timeRegardAsEnding = strategyDetailVO.getTimeRegardAsEnding(); |
| | | |
| | | Integer backupPower = strategyDetailVO.getBackupPower(); |
| | | Integer destToPassenger = strategyDetailVO.getDestToPassenger(); |
| | | Integer endingTimeToUseTime = strategyDetailVO.getEndingTimeToUseTime(); |
| | | LocalDateTime rideTime = xpOrder.getRideTime(); |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | Optional<XpOrder> luckyOrderOpt = servingVehicles.getData().stream() |
| | | //获取位置 |
| | | .map(vin -> mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class)) |
| | | .map(VehiclePosition::getOrderId) |
| | | .map(xpOrderClient::queryOrderById) |
| | | .filter(R::isSuccess) |
| | | .map(R::getData) |
| | | .filter(o -> { |
| | | XpVehicle xpVehicle = xpVehicleClient.queryById(o.getVehicleId()).getData(); |
| | | Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(o.getAppUserId().toString())); |
| | | RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class); |
| | | if (routeRemain.getDuration() / 60 > timeRegardAsEnding) { |
| | | return false; |
| | | } |
| | | if (routeRemain.getDistance() > distanceRegardAsEnding) { |
| | | return false; |
| | | } |
| | | if (routeRemain.getDuration() / 60 > timeRegardAsEnding) { |
| | | return false; |
| | | } |
| | | RouteAndFareDto next = new RouteAndFareDto(); |
| | | next.setOrigin(new LonLatDto(o.getStartLon(),o.getStartLat())); |
| | | next.setDestination(new LonLatDto(o.getEndLon(),o.getEndLat())); |
| | | RouteVo route = xpMapClient.getDistanceAndDuration(next).getData(); |
| | | if (route.getDistance() > backupPower + xpVehicle.getMileageRange()) |
| | | return false; |
| | | return routeRemain.getDistance() < destToPassenger |
| | | || now.plusSeconds(routeRemain.getDuration()) |
| | | .plusMinutes(endingTimeToUseTime) |
| | | .isBefore(rideTime); |
| | | }) |
| | | .findAny(); |
| | | |
| | | if (luckyOrderOpt.isPresent()) { |
| | | XpOrder luckyOder = luckyOrderOpt.get(); |
| | | log.info("有空闲车辆 {} 订单 {}", luckyOder.getOrderNumber(), orderNo); |
| | | XpVehicle xpVehicle = xpVehicleClient.queryById(luckyOder.getVehicleId()).getData(); |
| | | // 设置路线信息 |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | | routeAndFareDto.setDestination(userPostion); |
| | | routeAndFareDto.setOrigin(new LonLatDto(luckyOder.getEndLon(),luckyOder.getEndLat())); |
| | | RouteVo routeToOrigin = xpMapClient.getDistanceAndDuration(routeAndFareDto).getData(); |
| | | Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(luckyOder.getAppUserId().toString())); |
| | | RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class); |
| | | routeToOrigin.getPolyline().addAll(0, routeRemain.getPolyline()); |
| | | routeToOrigin.setDuration(routeToOrigin.getDuration() + routeRemain.getDuration()); |
| | | routeToOrigin.setDistance(routeToOrigin.getDistance() + routeRemain.getDistance()); |
| | | PushOrderDto pushOrderDto = buildPushOrderDto(xpOrder); |
| | | pushOrderDto.setVin(xpVehicle.getVehicleVin()); |
| | | pushOrderDto.setTaskId(xpOrder.getXpuTaskId()); |
| | | // 订单流转 |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | redisService.setCacheObject(CacheConstants.nextOrder(luckyOder.getId().toString()), xpOrder.getId()); |
| | | redisService.setCacheObject(CacheConstants.navigationStart(xpOrder.getAppUserId().toString()), routeToOrigin); |
| | | redisService.removeByPattern(quoteName,xpOrder.getOrderNumber()); |
| | | log.info("将订单 {} 从队列 {} 弹出去", orderNo, quoteName); |
| | | break; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private static PushOrderDto buildPushOrderDto(XpOrder xpOrder) { |
| | | PushOrderDto pushOrderDto = new PushOrderDto(); |
| | | pushOrderDto.setOrderId(xpOrder.getId().toString()); |
| | | pushOrderDto.setStartLatitude(xpOrder.getStartLat()); |
| | | pushOrderDto.setStartLongitude(xpOrder.getStartLon()); |
| | | pushOrderDto.setEndLatitude(xpOrder.getEndLat()); |
| | | pushOrderDto.setEndLongitude(xpOrder.getEndLon()); |
| | | pushOrderDto.setEndPoiName(xpOrder.getEndPointName()); |
| | | pushOrderDto.setOrderType(OrderType.USER_ORDER); |
| | | pushOrderDto.setStage(1); |
| | | return pushOrderDto; |
| | | } |
| | | |
| | | private boolean isClose(XpOrder xpOrder,RouteAndFareDto routeAndFareDto) { |
| | | LonLatDto lonLatDto = new LonLatDto(xpOrder.getStartLon(), xpOrder.getStartLat()); |
| | | routeAndFareDto.setOrigin(lonLatDto); |
| | | return xpMapClient.getDistanceAndDuration(routeAndFareDto).getData().getDistance() < 800; |
| | | } |
| | | |
| | | @Resource |
| | | private MongoTemplate mongoTemplate; |
| | | |
| | | |
| | | /** |
| | | * 订单处理 |
| | | * 重新改派 |
| | | * 1.优化好点 做个倒计时的异步改派多次 |
| | | * @param count 轮数 |
| | | * @param uid |
| | | * @param uid 用户id |
| | | * @param longitude 经度 |
| | | * @param latitude 纬度 |
| | | * @param orderNo 订单号 |
| | | */ |
| | | @SneakyThrows |
| | | public void reassignPushOrder(int count, String uid, Double longitude, Double latitude, String orderNo) { |
| | | System.out.println("进入推单环环节"); |
| | | public XpOrderReassign reassignPushOrder(int count, String uid, Double longitude, Double latitude, String orderNo) { |
| | | log.info("进入推单环环节"); |
| | | if (count == 0) { |
| | | count = 1; |
| | | } |
| | | // 订单状态 |
| | | R<XpOrder> xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo); |
| | | if (xpOrderR.getCode() != 200) { |
| | | return; |
| | | return null; |
| | | } |
| | | // List<Integer> notDrive = new ArrayList<Integer>(){{ //未行驶的情况下订单故障状态点 status=2、3、4、5 |
| | | // add(OrderStatusEnum.READY_DEPART.getCode());add(OrderStatusEnum.PICK_UP.getCode()); |
| | | // add(OrderStatusEnum.PICK_UP_GUESTS.getCode());add(OrderStatusEnum.PASSENGER_BOARDED.getCode()); |
| | | // }}; |
| | | |
| | | if (xpOrderR.getData().getStatus() != 1) { |
| | | return; |
| | | return null; |
| | | } |
| | | |
| | | XpOrder data = xpOrderR.getData(); |
| | | XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null); |
| | | |
| | | XpOrderReassign entity = new XpOrderReassign(data.getId(),data.getVehicleId(),data.getFleetId(),longitude,latitude,"接驾故障"); |
| | | entity.setIsComplete(false); |
| | | entity.setAppUserId(Long.valueOf(uid)); |
| | | //循环找车 |
| | | for (int i = 0; i < count; i++) { |
| | | log.info("进入找车环节"); |
| | | List<VehiclePosition> positionList = vehiclePositionService.findAvailableVehiclesNearby(longitude, latitude, xpTradingStrategy.getOnePushDistance(), xpTradingStrategy.getSimultaneouslyOrderCount()); |
| | | |
| | | // 获取车辆的区域信息 |
| | | if (positionList.isEmpty()) { |
| | | continue; |
| | | log.info("没有找到空闲车辆 {},尝试连环派单给即将服务结束的车辆", orderNo); |
| | | // 查询状态为1的车辆vin |
| | | Set<String> vinList = positionList.stream().map(VehiclePosition::getVin).collect(Collectors.toSet()); |
| | | R<List<String>> servingVehicles = xpVehicleClient.queryVehiclePositionByVin(new VehiclePositionByVinDto(data.getFleetId(), vinList, xpTradingStrategy.getSimultaneouslyOrderCount(),1)); |
| | | if (servingVehicles.getCode() != 200) { |
| | | continue; |
| | | } |
| | | |
| | | LonLatDto userPosition = new LonLatDto(data.getStartLon(), data.getStartLat());//人的位置 |
| | | |
| | | XpTradingStrategyDetailVO strategyDetailVO = tradingStrategyClient.queryById().getData(); |
| | | |
| | | Integer distanceRegardAsEnding = strategyDetailVO.getDistanceRegardAsEnding(); |
| | | Integer timeRegardAsEnding = strategyDetailVO.getTimeRegardAsEnding(); |
| | | |
| | | Integer backupPower = strategyDetailVO.getBackupPower(); |
| | | Integer destToPassenger = strategyDetailVO.getDestToPassenger(); |
| | | Integer endingTimeToUseTime = strategyDetailVO.getEndingTimeToUseTime(); |
| | | LocalDateTime rideTime = data.getRideTime(); |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | Optional<XpOrder> luckyOrderOpt = servingVehicles.getData().stream() |
| | | //获取位置 |
| | | .map(vin -> mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class)) |
| | | .map(VehiclePosition::getOrderId) |
| | | .map(xpOrderClient::queryOrderById) |
| | | .filter(R::isSuccess) |
| | | .map(R::getData) |
| | | .filter(o -> { |
| | | XpVehicle xpVehicle = xpVehicleClient.queryById(o.getVehicleId()).getData(); |
| | | Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(o.getAppUserId().toString())); |
| | | RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class); |
| | | if (routeRemain.getDuration() / 60 > timeRegardAsEnding) { |
| | | return false; |
| | | } |
| | | if (routeRemain.getDistance() > distanceRegardAsEnding) { |
| | | return false; |
| | | } |
| | | if (routeRemain.getDuration() / 60 > timeRegardAsEnding) { |
| | | return false; |
| | | } |
| | | RouteAndFareDto next = new RouteAndFareDto(); |
| | | next.setOrigin(new LonLatDto(o.getStartLon(),o.getStartLat())); |
| | | next.setDestination(new LonLatDto(o.getEndLon(),o.getEndLat())); |
| | | RouteVo route = xpMapClient.getDistanceAndDuration(next).getData(); |
| | | if (route.getDistance() > backupPower + xpVehicle.getMileageRange()) |
| | | return false; |
| | | return routeRemain.getDistance() < destToPassenger |
| | | || now.plusSeconds(routeRemain.getDuration()) |
| | | .plusMinutes(endingTimeToUseTime) |
| | | .isBefore(rideTime); |
| | | }) |
| | | .findAny(); |
| | | |
| | | if (luckyOrderOpt.isPresent()) { |
| | | XpOrder luckyOder = luckyOrderOpt.get(); |
| | | log.info("有空闲车辆 {} 订单 {}", luckyOder.getOrderNumber(), orderNo); |
| | | XpVehicle xpVehicle = xpVehicleClient.queryById(luckyOder.getVehicleId()).getData(); |
| | | // 设置路线信息 |
| | | RouteAndFareDto pickUpRoute = new RouteAndFareDto(); |
| | | pickUpRoute.setDestination(userPosition); |
| | | pickUpRoute.setOrigin(new LonLatDto(luckyOder.getEndLon(),luckyOder.getEndLat())); |
| | | RouteVo routeToOrigin = xpMapClient.getDistanceAndDuration(pickUpRoute).getData(); |
| | | Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(luckyOder.getAppUserId().toString())); |
| | | RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class); |
| | | routeToOrigin.getPolyline().addAll(0, routeRemain.getPolyline()); |
| | | routeToOrigin.setDuration(routeToOrigin.getDuration() + routeRemain.getDuration()); |
| | | routeToOrigin.setDistance(routeToOrigin.getDistance() + routeRemain.getDistance()); |
| | | PushOrderDto pushOrderDto = buildPushOrderDto(data); |
| | | pushOrderDto.setVin(xpVehicle.getVehicleVin()); |
| | | // 订单流转 |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | redisService.setCacheObject(CacheConstants.nextOrder(luckyOder.getId().toString()), data.getId()); |
| | | redisService.setCacheObject(CacheConstants.navigationStart(data.getAppUserId().toString()), routeToOrigin); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // 直接派单 定义一个锁来锁定车辆 |
| | |
| | | continue; |
| | | } |
| | | // 关闭巡游单子 |
| | | R<Long> stringR = xpCruiseOrderClient.updateCruiseOrder(vehicleId1.getVehicleVin()); |
| | | R<?> stringR = xpCruiseOrderClient.cancelCruiseOrderByVin(vehicleId1.getVehicleVin()); |
| | | if (stringR == null || stringR.getData() == null) { |
| | | log.info("关闭巡游单子失败"); |
| | | continue; |
| | | } |
| | | |
| | | PushOrderDto pushOrderDto = new PushOrderDto(); |
| | | pushOrderDto.setTaskId(data.getXpuTaskId()); |
| | | pushOrderDto.setVin(vehiclePosition.getVin()); |
| | | pushOrderDto.setOrderId(data.getId().toString()); |
| | | pushOrderDto.setStartLatitude(data.getStartLat()); |
| | | pushOrderDto.setStartLongitude(data.getStartLon()); |
| | | pushOrderDto.setEndLatitude(data.getEndLat()); |
| | | pushOrderDto.setEndLongitude(data.getEndLon()); |
| | | pushOrderDto.setEndPoiName(data.getEndPointName()); |
| | | pushOrderDto.setOrderType(OrderType.USER_ORDER); |
| | | pushOrderDto.setStage(1); |
| | | // 调用推送服务 orderId + carVin |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | |
| | | } catch (Exception e) { |
| | | entity.setNewVehicleId(vehicleId1.getId()); |
| | | entity.setNewFleetId(vehicleId1.getFleetId()); |
| | | entity.setIsComplete(true); |
| | | // //接单成功 将 修改 订单的状态=1 ( 状态 0=已取消,1=待接单,2=待出发,3=接驾中,4=待客上车,5=乘客已上车,6=服务中,7=待客下车,8=待付款,9=待评价,10=已完成) |
| | | // orderCarStatus = true; |
| | | xpOrderClient.updateOrderStatus(data.getId(), OrderStatusEnum.PENDING_ORDER.getCode(), false); |
| | | redisService.setCacheObject("ORDER_STATUS:" + data.getId(), OrderStatusEnum.PENDING_ORDER.getCode(), 24L, TimeUnit.HOURS); |
| | | |
| | | break; |
| | | } catch (Exception e) { |
| | | throw new RuntimeException(e); |
| | | } finally { |
| | | lock.unlock(); |
| | | } |
| | | } |
| | | //保存改派记录 |
| | | return entity; |
| | | } |
| | | |
| | | |