Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi
| | |
| | | ALTER TABLE `xp_operations_user` MODIFY COLUMN `status` tinyint(1) NULL DEFAULT 1 COMMENT '状态 1=启用 0=禁用' AFTER `remarks` |
| | |
| | | ALTER TABLE `xp_task_0` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_1` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_2` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_3` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_4` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_5` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_6` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_7` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_8` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_9` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_10` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_11` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_12` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_13` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_14` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_15` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_16` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_17` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_18` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | | |
| | | ALTER TABLE `xp_task_19` ADD COLUMN `will_timeout_notice_sent` tinyint NOT NULL DEFAULT 0 COMMENT '事故即将超时通知是否已发送(0否1是)' AFTER `update_by`; |
| | |
| | | ALTER TABLE `xp_banner` ADD COLUMN `sort` int NULL DEFAULT NULL COMMENT '排序' AFTER `banner_status`; |
| | | |
| | | ALTER TABLE `xp_cruise_plan_vehicle` ADD COLUMN `id` bigint NOT NULL COMMENT '自增id' FIRST; |
| | | |
| | | ALTER TABLE `xp_cruise_plan_vehicle` ADD PRIMARY KEY (`id`) USING BTREE; |
| | | |
| | | ALTER TABLE `xp_cruise_plan_vehicle` MODIFY COLUMN `id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增id'; |
| | |
| | | private String startChargingPicture; |
| | | |
| | | @ApiModelProperty(value = "开始充电时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime startTime; |
| | | |
| | | @ApiModelProperty(value = "结束剩余电量") |
| | |
| | | private String endChargingPicture; |
| | | |
| | | @ApiModelProperty(value = "结束充电时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime endTime; |
| | | |
| | | @ApiModelProperty(value = "开始充电操作人") |
| | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * <p> |
| | | * 任务管理 |
| | |
| | | @ApiModelProperty(value = "是否已发送过期通知 0=未发送 1=已发送") |
| | | private Integer expiredNoticeSent; |
| | | |
| | | @ApiModelProperty(value = "事故即将超时通知是否已发送 0=未发送 1=已发送") |
| | | private Integer willTimeoutNoticeSent; |
| | | |
| | | @ApiModelProperty(value = "状态 0=待到达 1=待处理 2=已完成 3=已取消") |
| | | private Integer status; |
| | | |
| | |
| | | private Long vehicleId; |
| | | |
| | | @ApiModelProperty(value = "开始时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日", timezone = "GMT+8") |
| | | private LocalDate startTime; |
| | | |
| | | @ApiModelProperty(value = "结束时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日", timezone = "GMT+8") |
| | | private LocalDate endTime; |
| | | |
| | | @ApiModelProperty(value = "维修原因") |
| | |
| | | private Long sendUserId; |
| | | |
| | | @ApiModelProperty(value = "送修时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime sendTime; |
| | | |
| | | @ApiModelProperty(value = "取回人") |
| | | private Long returnUserId; |
| | | |
| | | @ApiModelProperty(value = "取回时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime returnTime; |
| | | |
| | | |
| | |
| | | break; |
| | | case ORDER_RECEIVED: |
| | | //收到订单 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.READY_DEPART, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId.contains("XU") ? orderId.substring(2) : orderId), OrderStatusEnum.READY_DEPART.getCode()); |
| | | if(!orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.READY_DEPART, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.READY_DEPART.getCode()); |
| | | } |
| | | break; |
| | | case ORDER_STARTED: |
| | | //开始执行订单 |
| | |
| | | break; |
| | | case ORDER_EN_ROUTE_TO_PICKUP: |
| | | //前往上车点 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PICK_UP, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId.contains("XU") ? orderId.substring(2) : orderId), OrderStatusEnum.PICK_UP.getCode()); |
| | | if(!orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PICK_UP, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.PICK_UP.getCode()); |
| | | } |
| | | break; |
| | | case ORDER_ARRIVED_AT_PICKUP: |
| | | //到达上车点 |
| | |
| | | break; |
| | | case ORDER_WAITING_FOR_PICKUP: |
| | | //等待乘客上车 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PICK_UP_GUESTS, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId.contains("XU") ? orderId.substring(2) : orderId), OrderStatusEnum.PICK_UP_GUESTS.getCode()); |
| | | if(!orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PICK_UP_GUESTS, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.PICK_UP_GUESTS.getCode()); |
| | | } |
| | | break; |
| | | case ORDER_PASSENGER_ONBOARD: |
| | | //乘客已上车 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PASSENGER_BOARDED, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId.contains("XU") ? orderId.substring(2) : orderId), OrderStatusEnum.PASSENGER_BOARDED.getCode()); |
| | | if(!orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PASSENGER_BOARDED, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.PASSENGER_BOARDED.getCode()); |
| | | } |
| | | break; |
| | | case ORDER_EN_ROUTE_TO_DESTINATION: |
| | | //前往目的地 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.IN_SERVICE, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId.contains("XU") ? orderId.substring(2) : orderId), OrderStatusEnum.IN_SERVICE.getCode()); |
| | | if(!orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.IN_SERVICE, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.IN_SERVICE.getCode()); |
| | | } |
| | | break; |
| | | case ORDER_ARRIVED_AT_DESTINATION: |
| | | //到达目的地 |
| | | log.info("到达目的地,不做任何处理:{}", orderId); |
| | | break; |
| | | case ORDER_WAITING_FOR_DROPOFF: |
| | | //等待乘客下车 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.SEE_OFF_GUESTS, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId.contains("XU") ? orderId.substring(2) : orderId), OrderStatusEnum.SEE_OFF_GUESTS.getCode()); |
| | | //等待乘客下车,开始倒计时发下巡游单 |
| | | if(!orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.SEE_OFF_GUESTS, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.SEE_OFF_GUESTS.getCode()); |
| | | } |
| | | break; |
| | | case ORDER_DROPOFF_COMPLETED: |
| | | //下车完成 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.APPROVAL_REJECTION, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId.contains("XU") ? orderId.substring(2) : orderId), OrderStatusEnum.APPROVAL_REJECTION.getCode()); |
| | | // 下发巡游任务 |
| | | R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.parseLong(orderId)); |
| | | if(xpOrderR.getCode()==200){ |
| | | XpOrder orderData = xpOrderR.getData(); |
| | | Long vehicleId =orderData.getVehicleId(); |
| | | R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(vehicleId); |
| | | if(xpVehicleR.getData()!=null){ |
| | | XpVehicle xpVehicle = xpVehicleR.getData(); |
| | | //订单结束,在添加导航数据之前先将车辆状态修改为空闲 |
| | | xpVehicleClient.updateVehicleStatus(new UpdateVehicleStateDto(xpVehicle.getVehicleVin(), 0)); |
| | | xpVehicle = xpVehicleClient.queryById(vehicleId).getData(); |
| | | |
| | | AddCruiseMissionDto addCruiseMissionDto = new AddCruiseMissionDto(); |
| | | addCruiseMissionDto.setOrder(orderData); |
| | | addCruiseMissionDto.setVehicle(xpVehicle); |
| | | xpCruiseOrderClient.addCruiseMission(addCruiseMissionDto); |
| | | } |
| | | if(!orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.APPROVAL_REJECTION, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.APPROVAL_REJECTION.getCode()); |
| | | } |
| | | break; |
| | | case ORDER_COMPLETED: |
| | |
| | | break; |
| | | case ORDER_CANCELLED: |
| | | //已取消 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.CANCELED, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId.contains("XU") ? orderId.substring(2) : orderId), OrderStatusEnum.CANCELED.getCode()); |
| | | if(!orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.CANCELED, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.CANCELED.getCode()); |
| | | } |
| | | break; |
| | | case ORDER_ARRIVED_AT_CRUISE_DESTINATION: |
| | | //到达巡游终点 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.COMPLETED, sequence); |
| | | if(orderId.contains("XU")){ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.COMPLETED, sequence); |
| | | } |
| | | break; |
| | | case ORDER_PAUSED: |
| | | //订单暂停 |
| | |
| | | } |
| | | |
| | | |
| | | // // 算距离 |
| | | // 算距离 |
| | | R<RouteVo> distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto); |
| | | if (distanceAndDuration.getCode() != 200) { |
| | | throw new ServiceException("获取导肮信息失败", I18nKeyConstant.PATH_NOT_FOUND); |
| | |
| | | |
| | | // 8. 构建响应对象 |
| | | RouteAndFareVo routeAndFareVo = new RouteAndFareVo(); |
| | | |
| | | // MOCK数据 |
| | | // RouteVo routeVo = new RouteVo(); |
| | | // routeVo.setDistance(3000); |
| | | // routeVo.setDuration(5); |
| | | // routeVo.setRouteID("1"); |
| | | // List<LonLatDto> routePolyline = Arrays.asList( |
| | | // // 起点:天府新谷 |
| | | // new LonLatDto(104.05363, 30.58937), |
| | | // |
| | | // // 途经点1:府城大道与交子北二路交叉口附近 |
| | | // new LonLatDto(104.05821, 30.58745), |
| | | // |
| | | // // 途经点2:交子大道与成汉南路交叉口 |
| | | // new LonLatDto(104.06418, 30.58492), |
| | | // |
| | | // // 途经点3:交子大道与万象南路交叉口 |
| | | // new LonLatDto(104.06975, 30.58321), |
| | | // |
| | | // // 途经点4:交子大道与益州大道交叉口 |
| | | // new LonLatDto(104.07366, 30.58198), |
| | | // |
| | | // // 终点:金融城(地铁站附近) |
| | | // new LonLatDto(104.076544, 30.581039) |
| | | // ); |
| | | // routeVo.setPolyline(routePolyline); |
| | | routeAndFareVo.setRoute(routeVo); |
| | | |
| | | |
| | | routeAndFareVo.setXpPricingCard(xpPricingCardVo); |
| | | |
| | | FareVo fareVo = new FareVo(); |
| | |
| | | |
| | | // 9. 设置费用信息 |
| | | fareVo.setOriginalFare(xpPricingCardVo.getTotalPrice()); |
| | | fareVo.setOriginalFareStr(fareVo.getOriginalFare() + ""); |
| | | fareVo.setOriginalFareStr(new BigDecimal(fareVo.getOriginalFare()).setScale(2, RoundingMode.HALF_UP).toString()); |
| | | if (userCouponVo != null) { |
| | | if(userCouponVo.getMoney()>fareVo.getOriginalFare()){ |
| | | fareVo.setDiscountAmount(fareVo.getOriginalFare()); |
| | |
| | | redisService.setCacheObject(key, voJsonStr, 5l, TimeUnit.MINUTES); |
| | | //缓存导航数据,用于下单后推送导航给车端和乘客端 |
| | | redisService.setCacheObject("ORDER_NAVIGATION_END_DATA:" + userId, JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS); |
| | | |
| | | |
| | | return routeAndFareVo; |
| | | } |
| | | |
| | |
| | | xpOrder.setCreateTime(LocalDateTime.now()); |
| | | |
| | | |
| | | // 计算距离 和 时间 |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | | LonLatDto lonLatDto = new LonLatDto(); |
| | | lonLatDto.setLongitude(xpPoint.getPointLon()); |
| | | lonLatDto.setLatitude(xpPoint.getPointLat()); |
| | | routeAndFareDto.setOrigin(lonLatDto); |
| | | |
| | | LonLatDto lonLatDto1 = new LonLatDto(); |
| | | lonLatDto1.setLongitude(endXpPoint.getPointLon()); |
| | | lonLatDto1.setLatitude(endXpPoint.getPointLat()); |
| | | routeAndFareDto.setDestination(lonLatDto1); |
| | | |
| | | XpOpenCity openCities = xpOpenCityMapper.selectById(dto.getOpenCityId()); |
| | | if (openCities == null) { |
| | | throw new ServiceException("获取城市信息失败", I18nKeyConstant.CITY_NOT_FOUND); |
| | |
| | | dto.setOpenCityId(xpOpenCity.getId()); |
| | | xpOrder.setCityCode(xpOpenCity.getCityCode()); |
| | | XpRoutePlan xpRoutePlan = xpRoutePlanMapper.selectOne(new LambdaQueryWrapper<XpRoutePlan>().eq(XpRoutePlan::getAuditStatus, 2).eq(XpRoutePlan::getCityCode, xpOpenCity.getCityCode())); |
| | | if (xpRoutePlan != null) { |
| | | routeAndFareDto.setRoutePlanRule(xpRoutePlan.getRoutePlanRule()); |
| | | } |
| | | R<RouteVo> distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto); |
| | | |
| | | Integer distance = 0; |
| | | Integer duration = 0; |
| | | if (distanceAndDuration.getCode() != 200) { |
| | | // throw new ServiceException("订单生成失败", I18nKeyConstant.ORDER_CREATE_FAIL); |
| | | Object cacheObject = redisService.getCacheObject("ORDER_NAVIGATION_END_DATA:" + uid); |
| | | if (cacheObject != null) { |
| | | RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class); |
| | | distance = routeVo.getDistance(); |
| | | duration = routeVo.getDuration(); |
| | | } |
| | | // distance = distanceAndDuration.getData().getDistance(); |
| | | // duration = distanceAndDuration.getData().getDuration(); |
| | | |
| | | |
| | | // 产生订单 |
| | | R<Long> addOrderR = xpOrderClient.addOrder(xpOrder); |
| | |
| | | // 和上车点进行判断是否<maxPushDistance |
| | | double v = FastDistanceCalculator.distanceFast(Double.parseDouble(lonLat.split(",")[1]), Double.parseDouble(lonLat.split(",")[0]), xpPoint.getPointLat(), xpPoint.getPointLon()); |
| | | if (v < maxPushDistance) { |
| | | String value = orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + routeAndFareDto.getRoutePlanRule(); |
| | | String value = orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + xpRoutePlan.getRoutePlanRule(); |
| | | if (isPriorityDispatch) { |
| | | // 头部 value 订单_经纬度_状态_用户id_订单编号_距离_时间 |
| | | redisService.addToHead(s, value); |
| | |
| | | } |
| | | |
| | | String key = CacheConstants.QUEUE_POINT_ID + "-" + xpPoint.getId() + "-" + xpPoint.getPointLon() + "," + xpPoint.getPointLat(); |
| | | redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + routeAndFareDto.getRoutePlanRule())); |
| | | redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + xpRoutePlan.getRoutePlanRule())); |
| | | log.info("订单推单:{} {}", key, redisService.getCacheList(key)); |
| | | xpOrder.setQueueName(key); |
| | | xpOrderClient.updateOrder(xpOrder); |
| | |
| | | xpGeoQueryEntity.setTimestamp(System.currentTimeMillis()); |
| | | geoQueryEntityService.save(xpGeoQueryEntity); |
| | | return orderId.toString(); |
| | | |
| | | // |
| | | // XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreaMapper.selectById(dto.getXpElectronicFenceAreaId()); |
| | | // // 获取电子围栏的车辆 |
| | | // R<List<XpVehicle>> vehicles = xpVehicleClient.listByFenceId(xpElectronicFenceArea.getElectronicId()); |
| | | // |
| | | |
| | | |
| | | // 产生订单 存订单数据 // 下发指令 消息推送用户端 |
| | | // return null; |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | xpPricingCardVo.setStartPrice(startPrice); |
| | | xpPricingCardVo.setDistancePrice(distancePrice); |
| | | xpPricingCardVo.setDurationPrice(durationPrice); |
| | | xpPricingCardVo.setTotalPrice(startPrice + distancePrice + durationPrice); |
| | | xpPricingCardVo.setTotalPrice(new BigDecimal(startPrice + distancePrice + durationPrice).setScale(2,RoundingMode.HALF_UP).doubleValue()); |
| | | // 里程 |
| | | xpPricingCardVo.setDistance(realDistance); |
| | | xpPricingCardVo.setDuration(realTime); |
| | |
| | | // 动态计算费用 |
| | | startPrice= new BigDecimal(startPrice).multiply(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); |
| | | amount = amount+startPrice; |
| | | xpPricingCardVo.setTotalPrice(amount); |
| | | xpPricingCardVo.setTotalPrice(new BigDecimal(amount).setScale(2,RoundingMode.HALF_UP).doubleValue()); |
| | | |
| | | |
| | | |
| New file |
| | |
| | | package com.xiaopeng.maintenance.config; |
| | | |
| | | import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; |
| | | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; |
| | | import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | import java.time.LocalTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.format.DateTimeFormatterBuilder; |
| | | |
| | | /** |
| | | * Jackson LocalTime 序列化/反序列化配置 |
| | | * |
| | | * <p>兼容前端以 HH:mm(无秒)传参的场景,同时支持 HH:mm:ss(带秒)。</p> |
| | | */ |
| | | @Configuration |
| | | public class JacksonLocalTimeConfig { |
| | | |
| | | /** |
| | | * LocalTime 反序列化:兼容 HH:mm / HH:mm:ss |
| | | */ |
| | | @Bean |
| | | public Jackson2ObjectMapperBuilderCustomizer localTimeDeserializerCustomizer() { |
| | | DateTimeFormatter parseFormatter = new DateTimeFormatterBuilder() |
| | | .appendPattern("HH:mm") |
| | | .optionalStart() |
| | | .appendPattern(":ss") |
| | | .optionalEnd() |
| | | .toFormatter(); |
| | | |
| | | DateTimeFormatter writeFormatter = DateTimeFormatter.ofPattern("HH:mm"); |
| | | |
| | | return builder -> { |
| | | builder.deserializerByType(LocalTime.class, new LocalTimeDeserializer(parseFormatter)); |
| | | builder.serializerByType(LocalTime.class, new LocalTimeSerializer(writeFormatter)); |
| | | }; |
| | | } |
| | | } |
| | | |
| | |
| | | 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.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | |
| | | /** |
| | | * 车辆详情-车辆调度-发车 收车 |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @ApiOperation(value = "车辆运维-车辆调度-发车/收车", tags = {"运维APP-车辆管理"}) |
| | | @PostMapping("/api/v1/vehicle/vehicleDispatchDeparture") |
| | | public R<String> vehicleDispatchDeparture(@RequestBody VehicleDispatchDepartureDTO dto) { |
| | |
| | | if(xpVehicle.getState()==1){ |
| | | return R.fail("车辆正在接单中"); |
| | | } |
| | | xpVehicle.setOperatingStatus(dto.getDepartureStatus()); |
| | | xpVehicleClient.updateVehicleById(xpVehicle); |
| | | |
| | | VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class); |
| | | if(vehiclePosition==null || vehiclePosition.getPoint()==null){ |
| | | return R.fail("车辆位置信息不存在"); |
| | | } |
| | | xpVehicle.setOperatingStatus(dto.getDepartureStatus()); |
| | | xpVehicleClient.updateVehicleById(xpVehicle); |
| | | // 发车 |
| | | if(dto.getDepartureStatus()==1){ |
| | | // 找车辆的任务 生成巡游单子 下发命令 |
| | |
| | | @PostMapping("/api/v1/vehicleRepair/saveReturnRepair") |
| | | public R<String> saveReturnRepair(@Validated @RequestBody XpVehicleRepairReturnDTO dto) { |
| | | Long id = tokenService.getLoginOperationUser().getId(); |
| | | if (dto.getRepairMoney().toString().length() > 200) { |
| | | throw new ServiceException("维修费用不能超过200字符", I18nKeyConstant.REPAIR_MONEY_TOO_LONG); |
| | | if (dto.getRepairMoney()>99999999.99) { |
| | | throw new ServiceException("维修费用不能超过10字符", I18nKeyConstant.REPAIR_MONEY_TOO_LONG); |
| | | } |
| | | xpVehicleRepairService.saveReturnRepair(dto,id); |
| | | return R.ok(); |
| | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalTime; |
| | | import java.time.LocalTime; |
| | | import java.util.List; |
| | | |
| | | @Data |
| New file |
| | |
| | | package com.xiaopeng.maintenance.job.base; |
| | | |
| | | import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; |
| | | import com.xiaopeng.maintenance.job.utils.SpringContextsUtil; |
| | | import org.quartz.Job; |
| | | import org.quartz.JobExecutionContext; |
| | | import org.quartz.JobExecutionException; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | public abstract class AbstractJob implements Job{ |
| | | protected Logger logger = LoggerFactory.getLogger(getClass()); |
| | | |
| | | @Override |
| | | public abstract void execute(JobExecutionContext context) throws JobExecutionException; |
| | | |
| | | protected XpPushMessageClient xpPushMessageClient; |
| | | |
| | | public AbstractJob(){ |
| | | this.xpPushMessageClient = SpringContextsUtil.getBean(XpPushMessageClient.class); |
| | | } |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.job.base; |
| | | |
| | | import org.quartz.*; |
| | | import org.quartz.impl.StdSchedulerFactory; |
| | | |
| | | import java.util.Date; |
| | | import java.util.Map; |
| | | |
| | | public class QuartzManager { |
| | | private static SchedulerFactory factory = new StdSchedulerFactory(); |
| | | private static final String TRIGGER_NAME_PREFIX = "TRIGGER_PREFIX_"; |
| | | private static final String JOB_NAME_PREFIX = "JOB_PREFIX_"; |
| | | |
| | | /** |
| | | * 添加定时任务:具体某个时间点执行一次的任务,如:在某个2015-06-01 12:00发送一条消息 |
| | | * |
| | | * @param jobName |
| | | * 具体的任务名+ID标识唯一 |
| | | * @param jobType |
| | | * @param date |
| | | * @param jp |
| | | */ |
| | | public synchronized static void addJob(Class<? extends Job> jobClass, String jobName, TimeJobType jobType, Date date, |
| | | Map<String, ? extends Object> jp) { |
| | | //logger.debug("ADD JOB {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date); |
| | | try { |
| | | Scheduler sched = factory.getScheduler(); |
| | | JobDetail job = JobBuilder.newJob(jobClass).withIdentity(JOB_NAME_PREFIX + jobName, jobType.getType()) |
| | | .setJobData(new JobDataMap(jp)).build(); |
| | | |
| | | SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() |
| | | .withRepeatCount(0) |
| | | .withMisfireHandlingInstructionFireNow(); |
| | | SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger() |
| | | .withIdentity(TRIGGER_NAME_PREFIX + jobName, jobType.getType()) |
| | | .startAt(date) |
| | | .withSchedule(scheduleBuilder) |
| | | .build(); |
| | | removeJob(jobName, jobType); |
| | | |
| | | sched.scheduleJob(job, trigger); |
| | | |
| | | if (!sched.isShutdown()) { |
| | | sched.start(); |
| | | } |
| | | } catch (Exception e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名) |
| | | * @param jobName |
| | | * @param time |
| | | */ |
| | | public synchronized static void modifyJobTime(String jobName,TimeJobType jobType, Date time) { |
| | | //logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time); |
| | | try { |
| | | JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType()); |
| | | TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType()); |
| | | |
| | | |
| | | Scheduler sched = factory.getScheduler(); |
| | | SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(key); |
| | | if(trigger == null) { |
| | | return; |
| | | } |
| | | Date oldTime = trigger.getStartTime(); |
| | | |
| | | if (oldTime.getTime() != time.getTime()) { |
| | | JobDetail jobDetail = sched.getJobDetail(jobKey); |
| | | Class<? extends Job> objJobClass = jobDetail.getJobClass(); |
| | | removeJob(jobName,jobType); |
| | | Map<String, Object> jp = jobDetail.getJobDataMap(); |
| | | addJob(objJobClass, jobName, jobType, time, jp); |
| | | } |
| | | } catch (Exception e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 移除一个任务 |
| | | * |
| | | * @param jobName |
| | | */ |
| | | public synchronized static void removeJob(String jobName, TimeJobType jobType) { |
| | | try { |
| | | JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType()); |
| | | TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType()); |
| | | Scheduler sched = factory.getScheduler(); |
| | | |
| | | JobDetail detail = sched.getJobDetail(jobKey); |
| | | if (detail != null) { |
| | | sched.pauseJob(jobKey); |
| | | sched.pauseTrigger(key);// 停止触发器 |
| | | sched.unscheduleJob(key);// 移除触发器 |
| | | sched.deleteJob(jobKey);// 删除任务 |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 启动所有定时任务 |
| | | */ |
| | | public synchronized static void startJobs() { |
| | | try { |
| | | Scheduler sched = factory.getScheduler(); |
| | | sched.start(); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 关闭所有定时任务 |
| | | */ |
| | | public synchronized static void shutdownJobs() { |
| | | try { |
| | | Scheduler sched = factory.getScheduler(); |
| | | if (!sched.isShutdown()) { |
| | | sched.shutdown(); |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.job.base; |
| | | |
| | | /** |
| | | * @Description 按时间点发布的任务类型 |
| | | * @date 2025年2月17日 下午7:22:28 |
| | | */ |
| | | public enum TimeJobType { |
| | | ELECTRONIC_EFFECT("electronic_effect","电子围栏生效"), |
| | | ELECTRONIC_FAILURE("electronic_failure","电子围栏失效"), |
| | | ACCIDENT_WILL_TIMEOUT("accident_will_timeout", "事故即将超时"), |
| | | ACCIDENT_TIMEOUT("accident_timeout", "事故超时"); |
| | | |
| | | |
| | | private String type; |
| | | private String desc; |
| | | private TimeJobType(String type, String desc) { |
| | | this.type = type; |
| | | this.desc = desc; |
| | | } |
| | | public String getType() { |
| | | return type; |
| | | } |
| | | public void setType(String type) { |
| | | this.type = type; |
| | | } |
| | | public String getDesc() { |
| | | return desc; |
| | | } |
| | | public void setDesc(String desc) { |
| | | this.desc = desc; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.job.exceptions; |
| | | |
| | | /** |
| | | * @文件说明:定时器任务执行异常 |
| | | * @版权所有:成都喜来达 |
| | | * @项目名称: fengsheng |
| | | * @创建者: Leeyns |
| | | * @创建日期: 2016年5月18日 |
| | | * @最近修改者:Leeyns |
| | | * @最近修改日期:2016年5月18日 |
| | | */ |
| | | public class TimeException extends Exception { |
| | | |
| | | /** |
| | | * TODO |
| | | */ |
| | | private static final long serialVersionUID = 5703430073981692250L; |
| | | |
| | | private String message; |
| | | |
| | | public TimeException() { |
| | | super(); |
| | | } |
| | | |
| | | public TimeException(String message) { |
| | | super(message); |
| | | this.message = message; |
| | | } |
| | | |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.job.jobs; |
| | | |
| | | import com.xiaopeng.api.model.operation.XpElectronicFence; |
| | | import com.xiaopeng.api.model.operation.XpElectronicFenceArea; |
| | | import com.xiaopeng.maintenance.job.base.AbstractJob; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.quartz.JobDataMap; |
| | | import org.quartz.JobExecutionContext; |
| | | import org.quartz.JobExecutionException; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 直播推送定时任务 |
| | | * @author Administrator |
| | | * |
| | | */ |
| | | @Slf4j |
| | | public class ElectronicEffectJob extends AbstractJob { |
| | | |
| | | public static final String effect = "electronicEffect_"; |
| | | public static final String failure = "electronicFailure_"; |
| | | |
| | | @Override |
| | | public void execute(JobExecutionContext context) |
| | | throws JobExecutionException { |
| | | JobDataMap maps = context.getMergedJobDataMap(); |
| | | Long electronicId = maps.getLong("id"); |
| | | Long type = maps.getLong("type"); |
| | | |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.job.jobs;//package com.xiaopeng.operation.job.jobs; |
| | | // |
| | | //import com.alibaba.fastjson2.JSONObject; |
| | | //import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | //import com.xiaopeng.api.model.order.XpOrder; |
| | | //import com.xiaopeng.common.core.enums.OrderStatusEnum; |
| | | //import com.xiaopeng.common.core.enums.PushMessageTypeEnum; |
| | | //import com.xiaopeng.operation.job.base.AbstractJob; |
| | | //import lombok.extern.slf4j.Slf4j; |
| | | //import org.quartz.JobDataMap; |
| | | //import org.quartz.JobExecutionContext; |
| | | //import org.quartz.JobExecutionException; |
| | | // |
| | | //import java.util.Date; |
| | | //import java.util.HashMap; |
| | | //import java.util.Map; |
| | | //import java.util.Objects; |
| | | // |
| | | ///** |
| | | // * 直播推送定时任务 |
| | | // * @author Administrator |
| | | // * |
| | | // */ |
| | | //@Slf4j |
| | | //public class OrderCancelJob extends AbstractJob { |
| | | // |
| | | // public static final String name = "orderCancel_"; |
| | | // |
| | | // @Override |
| | | // public void execute(JobExecutionContext context) |
| | | // throws JobExecutionException { |
| | | // JobDataMap maps = context.getMergedJobDataMap(); |
| | | // Long orderId = maps.getLong("id"); |
| | | // try { |
| | | // log.info("开始执行订单取消任务"); |
| | | // XpOrder xpOrder = xpOrderService.getById(orderId); |
| | | // if(Objects.nonNull(xpOrder)){ |
| | | // xpOrder.setStatus(OrderStatusEnum.CANCELED.getCode()); |
| | | // xpOrderService.updateById(xpOrder); |
| | | // log.info("订单取消状态修改完成"); |
| | | // // 消息推送 |
| | | // Map<String, Object> params = new HashMap<>(); |
| | | // Map<String, Object> content = new HashMap<>(); |
| | | // content.put("orderId",xpOrder.getId()); |
| | | // content.put("status",OrderStatusEnum.CANCELED.getCode()); |
| | | // params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc()); |
| | | // params.put("content", JSONObject.toJSONString(content)); |
| | | // params.put("timestamp", new Date().getTime()+""); |
| | | // String message = JSONObject.toJSONString(params); |
| | | // SendMessageDTO sendMessageDTO = new SendMessageDTO(); |
| | | // sendMessageDTO.setMessage(message); |
| | | // sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId())); |
| | | // xpPushMessageClient.sendStatus(sendMessageDTO); |
| | | // log.info("订单取消消息推送完毕"); |
| | | // } |
| | | // }catch(Exception e){ |
| | | // e.printStackTrace(); |
| | | // } |
| | | // } |
| | | // |
| | | //} |
| New file |
| | |
| | | package com.xiaopeng.maintenance.job.utils; |
| | | |
| | | import org.springframework.beans.BeansException; |
| | | import org.springframework.context.ApplicationContext; |
| | | import org.springframework.context.ApplicationContextAware; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | @Component |
| | | public class SpringContextsUtil implements ApplicationContextAware{ |
| | | |
| | | private static ApplicationContext applicationContext; |
| | | |
| | | @Override |
| | | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { |
| | | if (SpringContextsUtil.applicationContext == null) { |
| | | SpringContextsUtil.applicationContext = applicationContext; |
| | | } |
| | | } |
| | | // 获取applicationContext |
| | | public static ApplicationContext getApplicationContext() { |
| | | return applicationContext; |
| | | } |
| | | // 通过name获取 Bean. |
| | | public static Object getBean(String name) { |
| | | return getApplicationContext().getBean(name); |
| | | } |
| | | // 通过class获取Bean. |
| | | public static <T> T getBean(Class<T> clazz) { |
| | | return getApplicationContext().getBean(clazz); |
| | | } |
| | | // 通过name,以及Clazz返回指定的Bean |
| | | public static <T> T getBean(String name, Class<T> clazz) { |
| | | System.out.println(getApplicationContext().getBean(name, clazz)); |
| | | return getApplicationContext().getBean(name, clazz); |
| | | } |
| | | |
| | | } |
| | |
| | | private Long operationsUserId; |
| | | |
| | | @ApiModelProperty(value = "操作时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime operationTime; |
| | | |
| | | @ApiModelProperty(value = "开始剩余电量") |
| | |
| | | private String operatorEndName; |
| | | |
| | | @ApiModelProperty(value = "操作时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime operationTime; |
| | | |
| | | } |
| | |
| | | private String operatorEndName; |
| | | |
| | | @ApiModelProperty(value = "操作时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime operationTime; |
| | | |
| | | } |
| | |
| | | private String operatorEndName; |
| | | |
| | | @ApiModelProperty(value = "操作时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime operationTime; |
| | | |
| | | } |
| | |
| | | private String operatorEndName; |
| | | |
| | | @ApiModelProperty(value = "操作时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime operationTime; |
| | | |
| | | } |
| | |
| | | private String operatorEndName; |
| | | |
| | | @ApiModelProperty(value = "操作时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime operationTime; |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.xiaopeng.api.dto.pushMessage.AliPushMessageDTO; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.pushMessage.XpAliPushMessageClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.account.XpOperationsUserNotification; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.constant.AliPushTypeConstant; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.TaskTypeNotificationEnum; |
| | | import com.xiaopeng.common.core.utils.StringUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 事故任务通知支撑类 |
| | | * |
| | | * <p>用于事故任务相关定时通知的通用方法抽取。</p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-03-14 |
| | | */ |
| | | @Component |
| | | public class AccidentTaskNotificationSupport { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(AccidentTaskNotificationSupport.class); |
| | | |
| | | @Autowired |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Autowired |
| | | private XpAliPushMessageClient xpAliPushMessageClient; |
| | | |
| | | /** |
| | | * 解析 handleUserId(逗号分隔) |
| | | */ |
| | | public Set<Long> parseUserIds(String handleUserId) { |
| | | if (StringUtils.isBlank(handleUserId)) { |
| | | return Collections.emptySet(); |
| | | } |
| | | String[] parts = handleUserId.split(","); |
| | | Set<Long> userIds = new HashSet<>(); |
| | | for (String part : parts) { |
| | | if (StringUtils.isBlank(part)) { |
| | | continue; |
| | | } |
| | | try { |
| | | userIds.add(Long.valueOf(part.trim())); |
| | | } catch (NumberFormatException e) { |
| | | log.warn("任务接收人ID非法,handleUserId={}", handleUserId); |
| | | } |
| | | } |
| | | return userIds; |
| | | } |
| | | |
| | | /** |
| | | * 获取运维人员信息 |
| | | */ |
| | | public Map<Long, XpOperationsUser> fetchOperationUsers(Set<Long> userIds) { |
| | | if (CollectionUtils.isEmpty(userIds)) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | try { |
| | | R<List<XpOperationsUser>> result = xpOperationUserClient.listByIds(new ArrayList<>(userIds)); |
| | | if (result == null || CollectionUtils.isEmpty(result.getData())) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | return result.getData().stream() |
| | | .filter(Objects::nonNull) |
| | | .filter(u -> u.getId() != null) |
| | | .collect(Collectors.toMap(XpOperationsUser::getId, u -> u, (a, b) -> a)); |
| | | } catch (Exception e) { |
| | | log.error("获取运维人员信息失败", e); |
| | | return Collections.emptyMap(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 批量获取车辆信息 |
| | | */ |
| | | public Map<Long, XpVehicle> fetchVehicles(Set<Long> vehicleIds) { |
| | | if (CollectionUtils.isEmpty(vehicleIds)) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | try { |
| | | R<List<XpVehicle>> result = xpVehicleClient.listByIds(new ArrayList<>(vehicleIds)); |
| | | if (result == null || CollectionUtils.isEmpty(result.getData())) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | return result.getData().stream() |
| | | .filter(Objects::nonNull) |
| | | .filter(v -> v.getId() != null) |
| | | .collect(Collectors.toMap(XpVehicle::getId, v -> v, (a, b) -> a)); |
| | | } catch (Exception e) { |
| | | log.error("获取车辆信息失败", e); |
| | | return Collections.emptyMap(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 构建推送 body JSON |
| | | */ |
| | | public String buildPushBodyJson(String content, Integer strategyCode, Long taskId) { |
| | | Map<String, Object> param = new HashMap<>(); |
| | | param.put("content", content); |
| | | param.put("strategy", strategyCode); |
| | | param.put("type", TaskTypeNotificationEnum.ACCIDENT_TASK.getCode()); |
| | | param.put("id", taskId == null ? "0" : taskId.toString()); |
| | | return JSONObject.toJSONString(param); |
| | | } |
| | | |
| | | /** |
| | | * 批量构建通知记录(包含 notificationExt) |
| | | */ |
| | | public List<XpOperationsUserNotification> buildNotifications(List<XpOperationsUser> users, |
| | | Integer notificationType, |
| | | String content, |
| | | Long taskId, |
| | | String bodyJson) { |
| | | if (CollectionUtils.isEmpty(users)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | List<XpOperationsUserNotification> notifications = new ArrayList<>(); |
| | | for (XpOperationsUser user : users) { |
| | | if (user == null || user.getId() == null) { |
| | | continue; |
| | | } |
| | | XpOperationsUserNotification notification = new XpOperationsUserNotification(); |
| | | notification.setNotificationType(notificationType); |
| | | notification.setNotificationContent(content); |
| | | notification.setOperationsUserId(user.getId()); |
| | | notification.setDataId(taskId == null ? 0L : taskId); |
| | | notification.setReadStatus(0); |
| | | notification.setNotificationExt(bodyJson); |
| | | notifications.add(notification); |
| | | } |
| | | return notifications; |
| | | } |
| | | |
| | | /** |
| | | * 推送通知(按 deviceType 分组) |
| | | */ |
| | | public int pushToUsersByDeviceType(List<XpOperationsUser> users, String title, String bodyJson) { |
| | | if (CollectionUtils.isEmpty(users)) { |
| | | return 0; |
| | | } |
| | | Map<Integer, List<XpOperationsUser>> operationUserMap = users.stream() |
| | | .filter(u -> u != null && u.getDeviceType() != null && StringUtils.isNotBlank(u.getPhoneNumber())) |
| | | .collect(Collectors.groupingBy(XpOperationsUser::getDeviceType)); |
| | | |
| | | int pushCount = 0; |
| | | for (Map.Entry<Integer, List<XpOperationsUser>> entry : operationUserMap.entrySet()) { |
| | | List<XpOperationsUser> groupUsers = entry.getValue(); |
| | | if (CollectionUtils.isEmpty(groupUsers)) { |
| | | continue; |
| | | } |
| | | String account = groupUsers.stream() |
| | | .map(XpOperationsUser::getPhoneNumber) |
| | | .filter(StringUtils::isNotBlank) |
| | | .collect(Collectors.joining(",")); |
| | | if (StringUtils.isBlank(account)) { |
| | | continue; |
| | | } |
| | | try { |
| | | xpAliPushMessageClient.pushMessage(AliPushMessageDTO.builder() |
| | | .body(bodyJson) |
| | | .account(account) |
| | | .title(title) |
| | | .pushType(AliPushTypeConstant.MESSAGE) |
| | | .deviceType(entry.getKey()) |
| | | .build()); |
| | | pushCount++; |
| | | } catch (Exception e) { |
| | | log.error("事故任务推送失败,deviceType={}", entry.getKey(), e); |
| | | } |
| | | } |
| | | return pushCount; |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.account.XpOperationsUserNotification; |
| | | import com.xiaopeng.api.model.maintenance.XpTask; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.maintenance.TaskScheduleConstants; |
| | | import com.xiaopeng.common.core.enums.NotificationTypeEnum; |
| | | import com.xiaopeng.common.core.utils.StringUtils; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 事故任务超时检查定时任务 |
| | | * |
| | | * <p>每分钟执行一次,判断事故任务是否超时并发送通知。</p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-03-14 |
| | | */ |
| | | @Deprecated |
| | | public class AccidentTaskTimeoutCheckScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(AccidentTaskTimeoutCheckScheduleTask.class); |
| | | |
| | | private static final String TASK_NAME = "事故任务超时检查定时任务"; |
| | | |
| | | private static final String PUSH_TITLE = "事故超时警示"; |
| | | |
| | | private static final String CONTENT_TEMPLATE = |
| | | "车辆%s在%s发生的紧急事故已超时!"; |
| | | |
| | | @Autowired |
| | | private XpTaskMapper taskMapper; |
| | | |
| | | @Autowired |
| | | private XpOperationUserNotificationClient xpOperationUserNotificationClient; |
| | | |
| | | @Autowired |
| | | private AccidentTaskNotificationSupport notificationSupport; |
| | | |
| | | /** |
| | | * 每分钟执行一次 |
| | | */ |
| | | @Scheduled(cron = "0 * * * * ?") |
| | | public void executeAccidentTaskTimeoutCheck() { |
| | | log.info("========== 开始执行{} ==========", TASK_NAME); |
| | | |
| | | try { |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | |
| | | List<XpTask> tasks = queryTimeoutAccidentTasks(now); |
| | | if (CollectionUtils.isEmpty(tasks)) { |
| | | log.info("未找到超时事故任务,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | Set<Long> vehicleIds = tasks.stream() |
| | | .map(XpTask::getVehicleId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | Map<Long, XpVehicle> vehicleMap = notificationSupport.fetchVehicles(vehicleIds); |
| | | |
| | | Set<Long> allUserIds = new HashSet<>(); |
| | | for (XpTask task : tasks) { |
| | | allUserIds.addAll(notificationSupport.parseUserIds(task.getHandleUserId())); |
| | | } |
| | | Map<Long, XpOperationsUser> userMap = notificationSupport.fetchOperationUsers(allUserIds); |
| | | |
| | | int notifiedTaskCount = 0; |
| | | int notificationCount = 0; |
| | | int pushCount = 0; |
| | | List<XpOperationsUserNotification> allNotifications = new ArrayList<>(); |
| | | |
| | | for (XpTask task : tasks) { |
| | | try { |
| | | if (task == null || task.getId() == null) { |
| | | continue; |
| | | } |
| | | Set<Long> userIds = notificationSupport.parseUserIds(task.getHandleUserId()); |
| | | if (CollectionUtils.isEmpty(userIds)) { |
| | | log.warn("事故任务ID={} 未配置有效处理人,跳过通知", task.getId()); |
| | | continue; |
| | | } |
| | | |
| | | int affectedRows = markTimeoutNoticeSent(task.getId(), now); |
| | | if (affectedRows <= 0) { |
| | | continue; |
| | | } |
| | | |
| | | List<XpOperationsUser> users = userIds.stream() |
| | | .map(userMap::get) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(users)) { |
| | | log.warn("事故任务ID={} 未匹配到有效运维人员,跳过通知", task.getId()); |
| | | continue; |
| | | } |
| | | |
| | | String plateNumber = resolvePlateNumber(vehicleMap.get(task.getVehicleId())); |
| | | String vehicleLocation = StringUtils.defaultString(task.getVehicleLocation()); |
| | | String content = String.format(CONTENT_TEMPLATE, plateNumber, vehicleLocation); |
| | | |
| | | String bodyJson = notificationSupport.buildPushBodyJson( |
| | | content, |
| | | NotificationTypeEnum.ACCIDENT_TIMEOUT.getCode(), |
| | | task.getId() |
| | | ); |
| | | |
| | | allNotifications.addAll(notificationSupport.buildNotifications( |
| | | users, |
| | | NotificationTypeEnum.ACCIDENT_TIMEOUT.getCode(), |
| | | content, |
| | | task.getId(), |
| | | bodyJson |
| | | )); |
| | | |
| | | pushCount += notificationSupport.pushToUsersByDeviceType(users, PUSH_TITLE, bodyJson); |
| | | notifiedTaskCount++; |
| | | } catch (Exception e) { |
| | | log.error("处理超时事故任务通知失败,任务ID={}", task == null ? null : task.getId(), e); |
| | | } |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(allNotifications)) { |
| | | xpOperationUserNotificationClient.addNotificationBatch(allNotifications); |
| | | notificationCount = allNotifications.size(); |
| | | } |
| | | |
| | | log.info("========== {} 执行完成,任务数: {},通知记录数: {},推送次数: {} ==========", |
| | | TASK_NAME, notifiedTaskCount, notificationCount, pushCount); |
| | | } catch (Exception e) { |
| | | log.error("{}执行失败", TASK_NAME, e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 查询超时事故任务:endTime < now 且未发送超时通知 |
| | | */ |
| | | private List<XpTask> queryTimeoutAccidentTasks(LocalDateTime now) { |
| | | return taskMapper.selectList(new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ACCIDENT) |
| | | .in(XpTask::getStatus, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING) |
| | | .isNotNull(XpTask::getEndTime) |
| | | .lt(XpTask::getEndTime, now) |
| | | .eq(XpTask::getExpiredNoticeSent, 0)); |
| | | } |
| | | |
| | | /** |
| | | * 原子更新(抢占式)标记超时通知已发送 |
| | | */ |
| | | private int markTimeoutNoticeSent(Long taskId, LocalDateTime now) { |
| | | return taskMapper.update(null, new LambdaUpdateWrapper<XpTask>() |
| | | .set(XpTask::getExpiredNoticeSent, 1) |
| | | .eq(XpTask::getId, taskId) |
| | | .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ACCIDENT) |
| | | .in(XpTask::getStatus, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING) |
| | | .isNotNull(XpTask::getEndTime) |
| | | .lt(XpTask::getEndTime, now) |
| | | .eq(XpTask::getExpiredNoticeSent, 0)); |
| | | } |
| | | |
| | | private String resolvePlateNumber(XpVehicle vehicle) { |
| | | return vehicle == null ? "" : StringUtils.defaultString(vehicle.getPlateNumber()); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.account.XpOperationsUserNotification; |
| | | import com.xiaopeng.api.model.maintenance.XpTask; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRule; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.maintenance.TaskScheduleConstants; |
| | | import com.xiaopeng.common.core.enums.NotificationTypeEnum; |
| | | import com.xiaopeng.common.core.utils.StringUtils; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.time.Duration; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 事故任务即将超时检查定时任务 |
| | | * |
| | | * <p>每分钟执行一次,判断事故任务在即将超时窗口内并发送通知。</p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-03-14 |
| | | */ |
| | | @Deprecated |
| | | public class AccidentTaskWillTimeoutScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(AccidentTaskWillTimeoutScheduleTask.class); |
| | | |
| | | private static final String TASK_NAME = "事故任务即将超时检查定时任务"; |
| | | |
| | | private static final String PUSH_TITLE = "事故即将超时提示"; |
| | | |
| | | private static final String CONTENT_TEMPLATE = |
| | | "车辆%s在%s发生的紧急事故即将超时,剩余时间%s分钟,请及时到达现场!"; |
| | | |
| | | @Autowired |
| | | private XpTaskMapper taskMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleMapper taskRuleMapper; |
| | | |
| | | @Autowired |
| | | private XpOperationUserNotificationClient xpOperationUserNotificationClient; |
| | | |
| | | @Autowired |
| | | private AccidentTaskNotificationSupport notificationSupport; |
| | | |
| | | /** |
| | | * 每分钟执行一次 |
| | | */ |
| | | @Scheduled(cron = "0 * * * * ?") |
| | | public void executeAccidentTaskWillTimeoutCheck() { |
| | | log.info("========== 开始执行{} ==========", TASK_NAME); |
| | | |
| | | try { |
| | | XpTaskRule taskRule = getTaskRule(); |
| | | Integer processingTimeLimit = taskRule == null ? null : taskRule.getProcessingTimeLimit(); |
| | | Integer factorMinutes = calcWillTimeoutFactorMinutes(processingTimeLimit); |
| | | if (factorMinutes == null || factorMinutes <= 0) { |
| | | log.info("未配置有效处理时限或即将超时因子<=0,跳过执行,processingTimeLimit={}", processingTimeLimit); |
| | | return; |
| | | } |
| | | |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | LocalDateTime windowEnd = now.plusMinutes(factorMinutes); |
| | | |
| | | List<XpTask> tasks = queryWillTimeoutAccidentTasks(now, windowEnd); |
| | | if (CollectionUtils.isEmpty(tasks)) { |
| | | log.info("未找到即将超时事故任务,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | Set<Long> vehicleIds = tasks.stream() |
| | | .map(XpTask::getVehicleId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | Map<Long, XpVehicle> vehicleMap = notificationSupport.fetchVehicles(vehicleIds); |
| | | |
| | | Set<Long> allUserIds = new HashSet<>(); |
| | | for (XpTask task : tasks) { |
| | | allUserIds.addAll(notificationSupport.parseUserIds(task.getHandleUserId())); |
| | | } |
| | | Map<Long, XpOperationsUser> userMap = notificationSupport.fetchOperationUsers(allUserIds); |
| | | |
| | | int notifiedTaskCount = 0; |
| | | int notificationCount = 0; |
| | | int pushCount = 0; |
| | | List<XpOperationsUserNotification> allNotifications = new ArrayList<>(); |
| | | |
| | | for (XpTask task : tasks) { |
| | | try { |
| | | if (task == null || task.getId() == null) { |
| | | continue; |
| | | } |
| | | Set<Long> userIds = notificationSupport.parseUserIds(task.getHandleUserId()); |
| | | if (CollectionUtils.isEmpty(userIds)) { |
| | | log.warn("事故任务ID={} 未配置有效处理人,跳过通知", task.getId()); |
| | | continue; |
| | | } |
| | | |
| | | int affectedRows = markWillTimeoutNoticeSent(task.getId(), now, windowEnd); |
| | | if (affectedRows <= 0) { |
| | | continue; |
| | | } |
| | | |
| | | List<XpOperationsUser> users = userIds.stream() |
| | | .map(userMap::get) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(users)) { |
| | | log.warn("事故任务ID={} 未匹配到有效运维人员,跳过通知", task.getId()); |
| | | continue; |
| | | } |
| | | |
| | | String plateNumber = resolvePlateNumber(vehicleMap.get(task.getVehicleId())); |
| | | String vehicleLocation = StringUtils.defaultString(task.getVehicleLocation()); |
| | | String remainMinutes = String.valueOf(calcRemainMinutes(now, task.getEndTime())); |
| | | String content = String.format(CONTENT_TEMPLATE, plateNumber, vehicleLocation, remainMinutes); |
| | | |
| | | String bodyJson = notificationSupport.buildPushBodyJson( |
| | | content, |
| | | NotificationTypeEnum.ACCIDENT_WILL_TIMEOUT.getCode(), |
| | | task.getId() |
| | | ); |
| | | |
| | | allNotifications.addAll(notificationSupport.buildNotifications( |
| | | users, |
| | | NotificationTypeEnum.ACCIDENT_WILL_TIMEOUT.getCode(), |
| | | content, |
| | | task.getId(), |
| | | bodyJson |
| | | )); |
| | | |
| | | pushCount += notificationSupport.pushToUsersByDeviceType(users, PUSH_TITLE, bodyJson); |
| | | notifiedTaskCount++; |
| | | } catch (Exception e) { |
| | | log.error("处理即将超时事故任务通知失败,任务ID={}", task == null ? null : task.getId(), e); |
| | | } |
| | | } |
| | | |
| | | if (!CollectionUtils.isEmpty(allNotifications)) { |
| | | xpOperationUserNotificationClient.addNotificationBatch(allNotifications); |
| | | notificationCount = allNotifications.size(); |
| | | } |
| | | |
| | | log.info("========== {} 执行完成,任务数: {},通知记录数: {},推送次数: {} ==========", |
| | | TASK_NAME, notifiedTaskCount, notificationCount, pushCount); |
| | | } catch (Exception e) { |
| | | log.error("{}执行失败", TASK_NAME, e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取任务规则配置 |
| | | */ |
| | | private XpTaskRule getTaskRule() { |
| | | return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); |
| | | } |
| | | |
| | | /** |
| | | * 计算即将超时窗口(分钟):floor(processingTimeLimit * 0.2) |
| | | */ |
| | | private Integer calcWillTimeoutFactorMinutes(Integer processingTimeLimit) { |
| | | if (processingTimeLimit == null || processingTimeLimit <= 0) { |
| | | return 0; |
| | | } |
| | | return (int) Math.floor(processingTimeLimit * 0.2d); |
| | | } |
| | | |
| | | /** |
| | | * 查询即将超时事故任务:now < endTime <= windowEnd 且未发送即将超时通知 |
| | | */ |
| | | private List<XpTask> queryWillTimeoutAccidentTasks(LocalDateTime now, LocalDateTime windowEnd) { |
| | | return taskMapper.selectList(new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ACCIDENT) |
| | | .in(XpTask::getStatus, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING) |
| | | .isNotNull(XpTask::getEndTime) |
| | | .gt(XpTask::getEndTime, now) |
| | | .le(XpTask::getEndTime, windowEnd) |
| | | .eq(XpTask::getWillTimeoutNoticeSent, 0)); |
| | | } |
| | | |
| | | /** |
| | | * 原子更新(抢占式)标记即将超时通知已发送 |
| | | */ |
| | | private int markWillTimeoutNoticeSent(Long taskId, LocalDateTime now, LocalDateTime windowEnd) { |
| | | return taskMapper.update(null, new LambdaUpdateWrapper<XpTask>() |
| | | .set(XpTask::getWillTimeoutNoticeSent, 1) |
| | | .eq(XpTask::getId, taskId) |
| | | .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ACCIDENT) |
| | | .in(XpTask::getStatus, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING) |
| | | .isNotNull(XpTask::getEndTime) |
| | | .gt(XpTask::getEndTime, now) |
| | | .le(XpTask::getEndTime, windowEnd) |
| | | .eq(XpTask::getWillTimeoutNoticeSent, 0)); |
| | | } |
| | | |
| | | /** |
| | | * 计算剩余分钟数(向上取整,避免出现 0 分钟) |
| | | */ |
| | | private long calcRemainMinutes(LocalDateTime now, LocalDateTime endTime) { |
| | | if (endTime == null) { |
| | | return 0; |
| | | } |
| | | long seconds = Duration.between(now, endTime).getSeconds(); |
| | | if (seconds <= 0) { |
| | | return 0; |
| | | } |
| | | return (seconds + 59) / 60; |
| | | } |
| | | |
| | | private String resolvePlateNumber(XpVehicle vehicle) { |
| | | return vehicle == null ? "" : StringUtils.defaultString(vehicle.getPlateNumber()); |
| | | } |
| | | } |
| | |
| | | /** |
| | | * 每5分钟执行一次 |
| | | */ |
| | | @Scheduled(cron = "0 */5 * * * ?") |
| | | @Scheduled(fixedRate = 60*1000) |
| | | public void clockInScheduleTask() { |
| | | log.info("========== 开始执行打卡检查 =========="); |
| | | try { |
| | | // 查询下班卡在今天的 |
| | | List<XpSchedulingDetail> clockOutPlanList = xpSchedulingDetailService.list(Wrappers.lambdaQuery(XpSchedulingDetail.class) |
| | | .likeRight(XpSchedulingDetail::getPlanTime, LocalDate.now())); |
| | | |
| | | // 下班卡在昨天的 |
| | | List<XpSchedulingDetail> clockOutPlanListLast = xpSchedulingDetailService.list(Wrappers.lambdaQuery(XpSchedulingDetail.class) |
| | | .likeRight(XpSchedulingDetail::getPlanTime, LocalDate.now().minusDays(1))); |
| | | |
| | | if(!CollectionUtils.isEmpty(clockOutPlanList)){ |
| | | List<Long> fleetIds = clockOutPlanList.stream().map(XpSchedulingDetail::getFleetId).collect(Collectors.toList()); |
| | |
| | | } |
| | | } |
| | | |
| | | // if (!CollectionUtils.isEmpty(clockOutPlanListLast)){ |
| | | // List<Long> fleetIds = clockOutPlanListLast.stream().map(XpSchedulingDetail::getFleetId).distinct().collect(Collectors.toList()); |
| | | // // 查询所有车队的绑定人员 |
| | | // List<XpFleetOperations> xpFleetOperations = xpFleetOperationsClient.getOperationsIdsByFleetIds(fleetIds).getData(); |
| | | // // 查询班次 |
| | | // List<Long> shiftIds = clockOutPlanListLast.stream().map(XpSchedulingDetail::getShiftId).collect(Collectors.toList()); |
| | | // List<XpShift> xpShifts = xpShiftService.list(Wrappers.lambdaQuery(XpShift.class) |
| | | // .in(XpShift::getId, shiftIds)); |
| | | // log.info("========== 查询到{}个车队 ==========", xpFleetOperations.size()); |
| | | // |
| | | // // 处理下班卡缺卡情况 |
| | | // // 过滤当前时间在班次下班打卡时间之后5小时的数据 今日已过下班打卡时间5小时后的班次 |
| | | // List<XpShift> shiftListFive = xpShifts.stream().filter(xpShift -> |
| | | // DateUtils.stringToLocalDateTime(LocalDate.now().minusDays(1) + " " + xpShift.getEndTime() + ":00").plusHours(5).isBefore(LocalDateTime.now())).collect(Collectors.toList()); |
| | | // List<Long> fiveIds = shiftListFive.stream().map(XpShift::getId).collect(Collectors.toList()); |
| | | // if(!CollectionUtils.isEmpty(fiveIds)){ |
| | | // log.info("========== 进入下班过期的班次 =========="); |
| | | // // 获取过期当前班次的排班明细 覆盖 |
| | | // List<XpSchedulingDetail> fiveClockOutPlans = clockOutPlanListLast.stream().filter(xpSchedulingDetail -> fiveIds.contains(xpSchedulingDetail.getShiftId())).collect(Collectors.toList()); |
| | | // List<Long> fiveFleetIdIn = fiveClockOutPlans.stream().map(XpSchedulingDetail::getFleetId).collect(Collectors.toList()); |
| | | // // 查询所有车队的绑定人员 |
| | | // if(!CollectionUtils.isEmpty(xpFleetOperations)){ |
| | | // List<Long> operationsUserIdsFive = xpFleetOperations.stream().filter(x -> fiveFleetIdIn.contains(x.getFleetId())) |
| | | // .map(XpFleetOperations::getOperationsUserId).distinct().collect(Collectors.toList()); |
| | | // // 批量查询人员打卡信息 |
| | | // List<XpClockIn> clockInListFive = xpClockInService.list(Wrappers.lambdaQuery(XpClockIn.class) |
| | | // .in(XpClockIn::getAppUserId, operationsUserIdsFive) |
| | | // .isNull(XpClockIn::getClockOutTime)); |
| | | // log.info("========== 获取到{}个人员没有下班打卡信息 ==========", clockInListFive.size()); |
| | | // if(!CollectionUtils.isEmpty(clockInListFive)){ |
| | | // for (XpClockIn xpClockIn : clockInListFive) { |
| | | // xpClockIn.setClockOutTime(LocalDateTime.now()); |
| | | // xpClockIn.setClockOutResult(3); |
| | | // } |
| | | // xpClockInService.updateBatchById(clockInListFive); |
| | | // log.info("========== 修改为下班缺卡 =========="); |
| | | // } |
| | | // } |
| | | // } |
| | | // } |
| | | |
| | | } catch (Exception e) { |
| | | log.error("执行打卡检查任务执行失败", e); |
| | | } |
| | |
| | | |
| | | PageInfo<TaskPageListVO> pageList(TaskPageListQuery query); |
| | | |
| | | void saveVehicleAccident(SaveVehicleAccidentDto dto, XpOperationsUser xpOperationsUser); |
| | | XpTask saveVehicleAccident(SaveVehicleAccidentDto dto, XpOperationsUser xpOperationsUser); |
| | | |
| | | R<TaskAccidentDetailVO> vehicleAccidentDetail(Long id); |
| | | |
| | |
| | | if (Objects.nonNull(operationsUserEnd)) { |
| | | xpChargingRecordVO.setOperatorEndName(operationsUserEnd.getNickName()); |
| | | } |
| | | xpChargingRecordVO.setStartMileageRange(Objects.nonNull(xpChargingRecord.getStartMileageRange()) ? xpChargingRecord.getStartMileageRange() : 0F); |
| | | xpChargingRecordVO.setEndMileageRange(Objects.nonNull(xpChargingRecord.getEndMileageRange()) ? xpChargingRecord.getEndMileageRange() : 0F); |
| | | return xpChargingRecordVO; |
| | | } |
| | | |
| | |
| | | public R<String> clockIn(ClockDTO dto) { |
| | | |
| | | XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId()); |
| | | if (null == xpCheckLocation) { |
| | | return R.fail("打卡地址不存在"); |
| | | } |
| | | if (xpCheckLocation.getStatus() == 0) { |
| | | return R.fail("打卡地址已禁用"); |
| | | } |
| | | |
| | | Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon() + "," + dto.getUserLat(), xpCheckLocation.getLocationLon() + "," + xpCheckLocation.getLocationLat()); |
| | | if (null != distance) { |
| | |
| | | public R<String> clockOut(ClockDTO dto) { |
| | | |
| | | XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId()); |
| | | if (null == xpCheckLocation) { |
| | | return R.fail("打卡地址不存在"); |
| | | } |
| | | if (xpCheckLocation.getStatus() == 0) { |
| | | return R.fail("打卡地址已禁用"); |
| | | } |
| | | Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon() + "," + dto.getUserLat(), xpCheckLocation.getLocationLon() + "," + xpCheckLocation.getLocationLat()); |
| | | if (null != distance) { |
| | | Double distance1 = distance.get("WGS84"); |
| | |
| | | @Override |
| | | @Transactional |
| | | @ShardingSphereTransactionType(TransactionType.BASE) |
| | | public void saveVehicleAccident(SaveVehicleAccidentDto dto, XpOperationsUser xpOperationsUser) { |
| | | public XpTask saveVehicleAccident(SaveVehicleAccidentDto dto, XpOperationsUser xpOperationsUser) { |
| | | XpTask xpTask = new XpTask(); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | String code = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); |
| | |
| | | // 根据事故处理限时配置设置任务截止时间 |
| | | LocalDateTime endTime = LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit()); |
| | | xpTask.setEndTime(endTime); |
| | | xpTask.setExpiredNoticeSent(0); |
| | | xpTask.setWillTimeoutNoticeSent(0); |
| | | this.save(xpTask); |
| | | if (xpTask.getId() == null && StringUtils.isNotBlank(xpTask.getTaskCode())) { |
| | | XpTask savedTask = this.getOne(new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getTaskCode, xpTask.getTaskCode()) |
| | | .last("limit 1")); |
| | | if (savedTask != null && savedTask.getId() != null) { |
| | | xpTask.setId(savedTask.getId()); |
| | | } |
| | | } |
| | | |
| | | // 异步发送消息通知 |
| | | String plateNumber = Objects.nonNull(vehicle) ? vehicle.getPlateNumber() : ""; |
| | | sendAccidentNotificationAsync(xpTask, plateNumber, taskRule.getProcessingTimeLimit()); |
| | | return xpTask; |
| | | } |
| | | |
| | | /** |
| | |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); |
| | | task.setExpiredNoticeSent(0); |
| | | task.setWillTimeoutNoticeSent(0); |
| | | task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE); |
| | | task.setCreateBy("系统自动生成"); |
| | | task.setCreateTime(LocalDateTime.now()); |
| | |
| | | @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())); |
| | | } |
| | | task.setAssigneeTime(LocalDateTime.now()); |
| | | task.setHandleUserId(handlerUserId.toString()); |
| | | task.setVehicleId(null); |
| | |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | String code = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); |
| | | task.setTaskCode(code); |
| | | // 查询规则 |
| | | XpTaskRule taskRule = xpTaskRuleMapper.selectOne(null); |
| | | if (taskRule != null) { |
| | | task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); |
| | | } |
| | | task.setTaskCategory(2); |
| | | // todo 临时处理 |
| | | task.setHandleUserId("1"); |
| | | task.setTaskTypeId(dto.getTaskTypeId()); |
| | | task.setTaskUrgencyLevel(dto.getTaskUrgencyLevel()); |
| | | task.setTaskDescription(dto.getTaskDescription()); |
| | |
| | | task.setVehicleLat(dto.getVehicleLat()); |
| | | task.setReportUserId(reportUserId); |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setExpiredNoticeSent(0); |
| | | task.setWillTimeoutNoticeSent(0); |
| | | saveTask.add(task); |
| | | } |
| | | this.saveBatch(saveTask); |
| | |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.maintenance.XpVehiclePreparation; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.maintenance.model.query.XpVehiclePreparationPageQuery; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.maintenance.XpVehiclePreparationDetailVO; |
| | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.beans.BeanUtils; |
| | | 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.stereotype.Service; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | @Autowired |
| | | private MongoTemplate mongoTemplate; |
| | | |
| | | |
| | | @Override |
| | |
| | | case 2: |
| | | // 充电记录 |
| | | operationRecords = xpChargingRecordMapper.operationRecords(query); |
| | | if(!CollectionUtils.isEmpty(operationRecords)){ |
| | | for (OperationRecordsVO operationRecord : operationRecords) { |
| | | operationRecord.setStartMileageRange(Objects.isNull(operationRecord.getStartMileageRange())?0.0f:operationRecord.getStartMileageRange()); |
| | | operationRecord.setEndMileageRange(Objects.isNull(operationRecord.getEndMileageRange())?0.0f:operationRecord.getEndMileageRange()); |
| | | } |
| | | } |
| | | break; |
| | | case 3: |
| | | // 检测记录 |
| | |
| | | return pageInfo; |
| | | } |
| | | |
| | | List<Long> userIds = operationRecords.stream().map(OperationRecordsVO::getOperationsUserId).collect(Collectors.toList()); |
| | | List<Long> userIds = operationRecords.stream().map(OperationRecordsVO::getOperationsUserId).distinct().collect(Collectors.toList()); |
| | | // 查询操作人信息 |
| | | R<List<XpOperationsUser>> listR = xpOperationUserClient.listByIds(userIds); |
| | | List<XpOperationsUser> xpOperationsUsers = listR.getData(); |
| | |
| | | xpVehicleRepair.setRepairMoneyDetail(dto.getRepairMoneyDetail()); |
| | | xpVehicleRepair.setReturnUserId(id); |
| | | xpVehicleRepair.setReturnTime(LocalDateTime.now()); |
| | | this.updateById(xpVehicleRepair); |
| | | } |
| | | } |
| | |
| | | welcome.message=欢迎来到我们的应用程序! |
| | | task.not.exist=任务不存在 |
| | | vehicle.not.exist=车辆不存在 |
| | | repair.money.too.long=维修费用不能超过200字符 |
| | | repair.money.too.long=维修费用不能超过10字符 |
| | |
| | | welcome.message=Welcome to our application! |
| | | 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 200 characters |
| | | repair.money.too.long=The maintenance cost cannot exceed 10 characters |
| | | task.rule.not.config=The vehicle accident task allocation rules have not been configured |
| | |
| | | welcome.message=欢迎来到我们的应用程序! |
| | | task.not.exist=任务不存在 |
| | | vehicle.not.exist=车辆不存在 |
| | | repair.money.too.long=维修费用不能超过200字符 |
| | | repair.money.too.long=维修费用不能超过10字符 |
| | | task.rule.not.config=未配置车辆事故任务分配规则 |
| | |
| | | |
| | | @Autowired |
| | | private XpGeoFencingPolygonService xpGeoFencingPolygonService; |
| | | // 自定义线程池配置 |
| | | private static final int CORE_POOL_SIZE = 5; // 核心线程数 |
| | | private static final int MAX_POOL_SIZE = 10; // 最大线程数 |
| | | private static final long KEEP_ALIVE_TIME = 60L; // 线程空闲存活时间 |
| | | private static final int QUEUE_CAPACITY = 100; // 阻塞队列容量 |
| | | |
| | | // 创建自定义线程池 |
| | | private final ExecutorService customThreadPool = new ThreadPoolExecutor( |
| | | CORE_POOL_SIZE, |
| | | MAX_POOL_SIZE, |
| | | KEEP_ALIVE_TIME, |
| | | TimeUnit.SECONDS, |
| | | new LinkedBlockingQueue<>(QUEUE_CAPACITY), |
| | | new ThreadFactory() { |
| | | private final AtomicInteger threadNumber = new AtomicInteger(1); |
| | | @Override |
| | | public Thread newThread(Runnable r) { |
| | | Thread t = new Thread(r, "route-check-thread-" + threadNumber.getAndIncrement()); |
| | | t.setDaemon(true); // 设置为守护线程,避免应用关闭时线程未停止 |
| | | return t; |
| | | } |
| | | }, |
| | | new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:调用线程执行 |
| | | ); |
| | | |
| | | // public RouteVo getDistanceAndTime(LonLatDto start, LonLatDto end, String avoidRoads, String fenceId, Integer routePlanRule) { |
| | | // RouteVo routeVo = new RouteVo(); |
| | | // |
| | | // String url = "https://tsapi.amap.com/v1/route/price?key=" + key + "&extensions=all&start=" + start.getLongitude() + "," + start.getLatitude(); |
| | | // HashMap<String, Object> params = new HashMap<>(); |
| | | // params.put("extensions", "all"); |
| | | // params.put("start", start.getLongitude() + "," + start.getLatitude()); |
| | | // params.put("end", end.getLongitude() + "," + end.getLatitude()); |
| | | // params.put("routeUserType", 2); |
| | | // if (avoidRoads != null && !avoidRoads.isEmpty()) { |
| | | // params.put("voidPolygons", avoidRoads); |
| | | // } |
| | | // if (routePlanRule != null) { |
| | | // params.put("strategy", routePlanRule); |
| | | // } |
| | | // |
| | | // String post = HttpUtils.post(url, JSON.toJSONString(params)); |
| | | // System.out.println("高德地图返回结果:" + post); |
| | | // |
| | | // JSONObject jsonObject = JSON.parseObject(post); |
| | | // String data = jsonObject.getString("data"); |
| | | // JSONObject jsonObject1 = JSON.parseObject(data); |
| | | // JSONArray path = jsonObject1.getJSONArray("paths"); |
| | | // |
| | | // if (path == null || path.isEmpty()) { |
| | | // return null; |
| | | // } |
| | | // |
| | | // // 使用自定义线程池并行处理每个路径的围栏检查 |
| | | // List<Future<PathCheckResult>> futures = new ArrayList<>(); |
| | | // CountDownLatch latch = new CountDownLatch(path.size()); // 用于等待所有任务完成 |
| | | // |
| | | // // 提交每个路径的处理任务 |
| | | // for (int j = 0; j < path.size(); j++) { |
| | | // final int index = j; |
| | | // JSONObject pathObject = path.getJSONObject(index); |
| | | // |
| | | // Future<PathCheckResult> future = customThreadPool.submit(() -> { |
| | | // try { |
| | | // PathCheckResult result = new PathCheckResult(); |
| | | // result.setIndex(index); |
| | | // result.setPathObject(pathObject); |
| | | // |
| | | // String points = pathObject.getString("points"); |
| | | // String[] split = points.split(";"); |
| | | // |
| | | // // 检查点位是否在围栏内 |
| | | // boolean inFence = checkPointsInFence(split, fenceId); |
| | | // result.setInFence(inFence); |
| | | // |
| | | // return result; |
| | | // } finally { |
| | | // latch.countDown(); // 任务完成,计数器减1 |
| | | // } |
| | | // }); |
| | | // |
| | | // futures.add(future); |
| | | // } |
| | | // |
| | | // try { |
| | | // // 等待所有任务完成,设置超时时间 |
| | | // if (!latch.await(10, TimeUnit.SECONDS)) { |
| | | // System.out.println("路径检查任务超时"); |
| | | // // 取消所有未完成的任务 |
| | | // for (Future<PathCheckResult> future : futures) { |
| | | // if (!future.isDone()) { |
| | | // future.cancel(true); |
| | | // } |
| | | // } |
| | | // } |
| | | // } catch (InterruptedException e) { |
| | | // Thread.currentThread().interrupt(); |
| | | // System.out.println("路径检查任务被中断"); |
| | | // return null; |
| | | // } |
| | | // |
| | | // // 收集处理结果,找到第一个不在围栏内的路径 |
| | | // PathCheckResult validPathResult = null; |
| | | // |
| | | // for (Future<PathCheckResult> future : futures) { |
| | | // try { |
| | | // if (future.isDone() && !future.isCancelled()) { |
| | | // PathCheckResult result = future.get(); |
| | | // if (!result.isInFence()) { |
| | | // validPathResult = result; |
| | | // break; // 找到有效的就停止 |
| | | // } |
| | | // } |
| | | // } catch (InterruptedException | ExecutionException e) { |
| | | // System.out.println("获取路径检查结果失败: " + e.getMessage()); |
| | | // e.printStackTrace(); |
| | | // } |
| | | // } |
| | | // |
| | | // // 如果找到了有效路径,处理该路径数据 |
| | | // if (validPathResult != null) { |
| | | // JSONObject validPath = validPathResult.getPathObject(); |
| | | // String routeID = validPath.getString("routeID"); |
| | | // String points = validPath.getString("points"); |
| | | // String[] split = points.split(";"); |
| | | // |
| | | // Integer costTime = validPath.getInteger("costTime"); |
| | | // Integer distance = validPath.getInteger("distance"); |
| | | // |
| | | // routeVo.setDistance(distance); |
| | | // routeVo.setDuration(costTime); |
| | | // |
| | | // ArrayList<LonLatDto> lonLatDtos = new ArrayList<>(split.length); |
| | | // for (String s : split) { |
| | | // String[] split1 = s.split(","); |
| | | // LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])); |
| | | // lonLatDtos.add(lonLatDto); |
| | | // } |
| | | // routeVo.setPolyline(lonLatDtos); |
| | | // routeVo.setRouteID(routeID); |
| | | // |
| | | // return routeVo; |
| | | // } |
| | | // |
| | | // return null; |
| | | // } |
| | | /** |
| | | * 路径检查结果内部类 |
| | | */ |
| | | private static class PathCheckResult { |
| | | private int index; |
| | | private JSONObject pathObject; |
| | | private boolean inFence; // true: 所有点都在围栏内, false: 有点不在围栏内 |
| | | |
| | | public int getIndex() { |
| | | return index; |
| | | } |
| | | |
| | | public void setIndex(int index) { |
| | | this.index = index; |
| | | } |
| | | |
| | | public JSONObject getPathObject() { |
| | | return pathObject; |
| | | } |
| | | |
| | | public void setPathObject(JSONObject pathObject) { |
| | | this.pathObject = pathObject; |
| | | } |
| | | |
| | | public boolean isInFence() { |
| | | return inFence; |
| | | } |
| | | |
| | | public void setInFence(boolean inFence) { |
| | | this.inFence = inFence; |
| | | } |
| | | } |
| | | /** |
| | | * 检查路径点位是否在围栏内 |
| | | */ |
| | | private boolean checkPointsInFence(String[] points, String fenceId) { |
| | | // 取5分之一的点位进行检查 |
| | | for (int i = 0; i < points.length; i++) { |
| | | if (i % 5 == 0) { |
| | | String[] split1 = points[i].split(","); |
| | | LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])); |
| | | if (!xpGeoFencingPolygonService.isInFence(lonLatDto.getLongitude(), lonLatDto.getLatitude(), fenceId, "operating_area")) { |
| | | return false; // 有点位不在围栏内 |
| | | } |
| | | } |
| | | } |
| | | return true; // 所有检查的点都在围栏内 |
| | | } |
| | | |
| | | /** |
| | | * 根据起始点获取驾车距离 和 时间 以及避让区域 |
| | |
| | | |
| | | JSONObject jsonObject1 = JSON.parseObject(data); |
| | | JSONArray path = jsonObject1.getJSONArray("paths"); |
| | | log.info("开始判断导航路径是否在运营区域范围内 {}", fenceId); |
| | | for (Object o : path) { |
| | | JSONObject jsonObject2 = (JSONObject) o; |
| | | String routeID = jsonObject2.getString("routeID"); |
| | | String points = jsonObject2.getString("points"); |
| | | String[] split = points.split(";"); |
| | | int temp=0; |
| | | // 取5分之一的点位 |
| | | for (int i = 0; i < split.length; i++) { |
| | | if (i % 10 == 0) { |
| | | String[] split1 = split[i].split(","); |
| | | LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])); |
| | | if (!xpGeoFencingPolygonService.isInFence(lonLatDto.getLongitude(), lonLatDto.getLatitude(), fenceId, "operating_area")) { |
| | | temp++; |
| | | break; |
| | | } |
| | | } |
| | | List<LonLatDto> pointsArray = new ArrayList<>(); |
| | | for (String string : split) { |
| | | String[] split1 = string.split(","); |
| | | LonLatDto lonLatDto = new LonLatDto(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])); |
| | | pointsArray.add(lonLatDto); |
| | | } |
| | | ForkJoinPool pool = new ForkJoinPool(); // 创建ForkJoinPool对象(默认使用处理器的核心数作为线程池大小) |
| | | ArrayPointsTask arrayPointsTask = new ArrayPointsTask(pointsArray, fenceId); // 创建求和任务对象并传入数组作为参数(这里也可以传入数组的一部分作为参数来实现更细粒度的拆分) |
| | | Long temp = pool.invoke(arrayPointsTask); // 提交任务并等待处理完成(也可以使用submit方法提交任务并获取一个Future对象来异步获取结果) |
| | | pool.shutdown(); // 关闭ForkJoinPool(释放资源) |
| | | if(temp==0){ |
| | | Integer costTime = jsonObject2.getInteger("costTime"); |
| | | Integer distance = jsonObject2.getInteger("distance"); |
| | |
| | | } |
| | | routeVo.setPolyline(lonLatDtos); |
| | | routeVo.setRouteID(routeID); |
| | | log.info("导航 {} 在 {} 运营区域内", routeVo.getRouteID(), fenceId); |
| | | return routeVo; |
| | | } |
| | | } |
| | | |
| | | return null; |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | class ArrayPointsTask extends RecursiveTask<Long>{ |
| | | //最大定位集合阈值 |
| | | private final int THRESHOLD = 10; |
| | | //围栏ID |
| | | String fenceId; |
| | | //定位点集合 |
| | | List<LonLatDto> pointsArray; |
| | | |
| | | |
| | | public ArrayPointsTask(List<LonLatDto> pointsArray, String fenceId) { |
| | | this.pointsArray = pointsArray; |
| | | this.fenceId = fenceId; |
| | | } |
| | | |
| | | @Override |
| | | protected Long compute() { |
| | | if(this.pointsArray.size() > THRESHOLD){ |
| | | int num = this.pointsArray.size() / 2; |
| | | ArrayPointsTask task1 = new ArrayPointsTask(this.pointsArray.subList(0, num), fenceId); |
| | | ArrayPointsTask task2 = new ArrayPointsTask(this.pointsArray.subList(num, this.pointsArray.size()), fenceId); |
| | | task1.fork(); |
| | | task2.fork(); |
| | | return task1.join() + task2.join(); |
| | | }else{ |
| | | long temp = 0; |
| | | for (LonLatDto lonLatDto : this.pointsArray) { |
| | | if (!xpGeoFencingPolygonService.isInFence(lonLatDto.getLongitude(), lonLatDto.getLatitude(), fenceId, "operating_area")) { |
| | | temp++; |
| | | break; |
| | | } |
| | | } |
| | | return temp; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 线路还原接口 |
| | | * 车端使用的数据 |
| | |
| | | */ |
| | | @ApiOperation(value = "订单查询轨迹路线") |
| | | @PostMapping("/api/v1/mini-program/order/queryOrderTrajectory") |
| | | public R<List<OrderTrajectory>> queryOrderTrajectory(@RequestParam Long orderId, HttpServletRequest request) { |
| | | public R<List<OrderTrajectory>> queryOrderTrajectory(@RequestParam String orderId, HttpServletRequest request) { |
| | | String uid = request.getHeader("XP-Uid"); |
| | | List<OrderTrajectory> trajectories = mongoTemplate.find( |
| | | new Query(Criteria.where("orderId").is(orderId)) |
| | |
| | | |
| | | import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient; |
| | | 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.order.XpCruiseOrder; |
| | | import com.xiaopeng.order.service.IXpCruiseOrderService; |
| | |
| | | protected IXpCruiseOrderService xpCruiseOrderService; |
| | | protected OrderMissionClient orderMissionClient; |
| | | protected XpVehicleClient xpVehicleClient; |
| | | protected UserVehicleClient userVehicleClient; |
| | | public AbstractJob(){ |
| | | this.xpOrderService = SpringContextsUtil.getBean(IXpOrderService.class); |
| | | this.xpPushMessageClient = SpringContextsUtil.getBean(XpPushMessageClient.class); |
| | |
| | | this.xpCruiseOrderService = SpringContextsUtil.getBean(IXpCruiseOrderService.class); |
| | | this.orderMissionClient = SpringContextsUtil.getBean(OrderMissionClient.class); |
| | | this.xpVehicleClient = SpringContextsUtil.getBean(XpVehicleClient.class); |
| | | this.userVehicleClient = SpringContextsUtil.getBean(UserVehicleClient.class); |
| | | } |
| | | |
| | | |
| | |
| | | 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.vehicleConvoy.CancelTaxiPassengerVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.order.job.base.AbstractJob; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | throws JobExecutionException { |
| | | JobDataMap maps = context.getMergedJobDataMap(); |
| | | Long orderId = maps.getLong("id"); |
| | | try { |
| | | log.info("开始执行添加任务"); |
| | | XpCruiseOrder xpCruiseOrder = xpCruiseOrderService.getById(orderId); |
| | | R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(xpCruiseOrder.getVehicleId()); |
| | | if(xpVehicleR.getData().getState()==0){ |
| | | PushOrderDto pushOrderDto = new PushOrderDto(); |
| | | pushOrderDto.setVin(xpCruiseOrder.getVehicleVin()); |
| | | pushOrderDto.setOrderId("XU" + xpCruiseOrder.getId()); |
| | | pushOrderDto.setStartLatitude(xpCruiseOrder.getStartLat()); |
| | | pushOrderDto.setStartLongitude(xpCruiseOrder.getStartLon()); |
| | | pushOrderDto.setEndLatitude(xpCruiseOrder.getEndLat()); |
| | | pushOrderDto.setEndLongitude(xpCruiseOrder.getEndLon()); |
| | | pushOrderDto.setOrderType(OrderType.CRUISE_ORDER); |
| | | pushOrderDto.setStage(2); |
| | | // 调用推送服务 orderId + carVin |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | | String appid = maps.getString("appid"); |
| | | XpOrder xpOrder = xpOrderService.getById(orderId); |
| | | // 解绑用户与车辆关系 |
| | | CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo(); |
| | | XpVehicle vehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); |
| | | if (vehicle != null) { |
| | | cancelTaxiPassengerVo.setVin(vehicle.getVehicleVin()); |
| | | cancelTaxiPassengerVo.setUid(xpOrder.getAppUserId().toString()); |
| | | cancelTaxiPassengerVo.setOrderNo(xpOrder.getOrderNumber()); |
| | | cancelTaxiPassengerVo.setAppId(appid); |
| | | userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo); |
| | | |
| | | // 修改车辆接单状态 |
| | | vehicle.setState(0); |
| | | xpVehicleClient.updateVehicleById(vehicle); |
| | | } |
| | | xpOrderService.addCruiseMission(vehicle, xpOrder); |
| | | } |
| | | |
| | | } |
| | |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.api.model.order.XpOrderTimeoutLog; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.order.job.base.AbstractJob; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | throws JobExecutionException { |
| | | JobDataMap maps = context.getMergedJobDataMap(); |
| | | Long orderId = maps.getLong("id"); |
| | | try { |
| | | try { |
| | | log.info("开始执行自动结束行程任务"); |
| | | XpOrder xpOrder = xpOrderService.getById(orderId); |
| | | xpOrderService.endTrip(xpOrder.getId(), String.valueOf(xpOrder.getAppUserId())); |
| | | if(xpOrder.getStatus() == 7){ |
| | | xpOrderService.endTrip(xpOrder.getId(), String.valueOf(xpOrder.getAppUserId())); |
| | | } |
| | | log.info("结束执行自动结束行程任务"); |
| | | // 添加超时记录 |
| | | XpOrderTimeoutLog xpOrderTimeoutLog = new XpOrderTimeoutLog(); |
| | | xpOrderTimeoutLog.setOrderId(xpOrder.getId()); |
| | | xpOrderTimeoutLog.setUserId(xpOrder.getAppUserId()); |
| | | xpOrderTimeoutLogService.save(xpOrderTimeoutLog); |
| | | |
| | | R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(xpOrder.getVehicleId()); |
| | | xpOrderService.addCruiseMission(xpVehicleR.getData(),xpOrder); |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | |
| | | if (userByMobile == null || userByMobile.getId() == null) { |
| | | return buildEmptyOrderPage(query); |
| | | } |
| | | query.setUid(userByMobile.getId()); |
| | | query.setUid(userByMobile.getUid()); |
| | | } |
| | | // 1. 构建查询条件 |
| | | LambdaQueryWrapper<XpOrder> wrapper = buildQueryWrapper(query); |
| | | if (CollUtil.isNotEmpty(vehicleIdsFilter)) { |
| | | wrapper.in(XpOrder::getVehicleId, vehicleIdsFilter); |
| | | } |
| | | wrapper.eq(Objects.nonNull(query.getUid()), XpOrder::getAppUserId, query.getUid()); |
| | | wrapper.orderByDesc(XpOrder::getCreateTime); |
| | | |
| | | // 2. 分页查询 |
| | |
| | | if (userByMobile == null || userByMobile.getId() == null) { |
| | | return new ArrayList<>(); |
| | | } |
| | | query.setUid(userByMobile.getId()); |
| | | query.setUid(userByMobile.getUid()); |
| | | } |
| | | wrapper.eq(Objects.nonNull(query.getUid()), XpOrder::getAppUserId, query.getUid()); |
| | | wrapper.orderByDesc(XpOrder::getCreateTime); |
| | | // 2. 查询订单列表 |
| | | List<XpOrder> orderList = this.list(wrapper); |
| | | |
| | |
| | | if (xpOrder.getStatus() == 0) { |
| | | return R.fail("订单已取消"); |
| | | } |
| | | xpOrder.setStatus(status); |
| | | if(xpOrder.getStatus() >= 8){ |
| | | return R.fail("订单已结束"); |
| | | } |
| | | switch (status) { |
| | | case 4: |
| | | // 查询起点点位 |
| | |
| | | xpOrder.setTripBegin(LocalDateTime.now()); |
| | | break; |
| | | case 7: |
| | | // 查询自动结束行程时间 |
| | | if (xpOrder.getOpenTrunk() != 1) { |
| | | Integer arriveTime = xpSystemSettingClient.getOrderFinishTime().getData(); |
| | | // 添加自动结束行程定时任务job |
| | | Map<String, ? extends Object> endTripJobMaps = |
| | | new ImmutableMap.Builder<String, Long>(). |
| | | put("id", xpOrder.getId()) |
| | | .build(); |
| | | QuartzManager.addJob( |
| | | EndTripJob.class, |
| | | (EndTripJob.name + xpOrder.getId()).toUpperCase(), |
| | | TimeJobType.END_TRIP, |
| | | DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(arriveTime)), |
| | | endTripJobMaps |
| | | ); |
| | | // 推送倒计时消息 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId", xpOrder.getId().toString()); |
| | | content.put("isOpen", 1); |
| | | params.put("type", PushMessageTypeEnum.OPEN_TRUNK.getDesc()); |
| | | params.put("content", JSONObject.toJSONString(content)); |
| | | params.put("timestamp", new Date().getTime() + ""); |
| | | String message = JSONObject.toJSONString(params); |
| | | SendMessageDTO sendMessageDTO = new SendMessageDTO(); |
| | | sendMessageDTO.setMessage(message); |
| | | sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId())); |
| | | xpPushMessageClient.sendStatus(sendMessageDTO); |
| | | } |
| | | 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 |
| | | ); |
| | | // 添加车辆到达终点后限停时间到后驶离的定时任务 |
| | | //时间到后添加巡游订单,解绑车辆关系,车辆驶离点位 |
| | | XpPoint point = xpPointClient.queryById(xpOrder.getEndPointId()).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 |
| | | ); |
| | | // 推送倒计时消息 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId", xpOrder.getId().toString()); |
| | | content.put("isOpen", 1); |
| | | params.put("type", PushMessageTypeEnum.OPEN_TRUNK.getDesc()); |
| | | params.put("content", JSONObject.toJSONString(content)); |
| | | params.put("timestamp", new Date().getTime() + ""); |
| | | String message = JSONObject.toJSONString(params); |
| | | SendMessageDTO sendMessageDTO = new SendMessageDTO(); |
| | | sendMessageDTO.setMessage(message); |
| | | sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId())); |
| | | xpPushMessageClient.sendStatus(sendMessageDTO); |
| | | break; |
| | | } |
| | | xpOrder.setStatus(status); |
| | | xpOrder.setAppUserId(null); |
| | | this.updateById(xpOrder); |
| | | return R.ok(); |
| | |
| | | exactMinutes = new BigDecimal(exactMinutes).setScale(2, RoundingMode.HALF_UP).doubleValue(); |
| | | order.setDuration(exactMinutes); |
| | | |
| | | // order.setMileageKilometers(80.0); |
| | | baseMapper.updateById(order); |
| | | // 解绑用户与车辆关系 |
| | | CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo(); |
| | | XpVehicle vehicle = xpVehicleClient.queryById(order.getVehicleId()).getData(); |
| | | if (vehicle != null) { |
| | | cancelTaxiPassengerVo.setVin(vehicle.getVehicleVin()); |
| | | cancelTaxiPassengerVo.setUid(uid); |
| | | cancelTaxiPassengerVo.setOrderNo(order.getOrderNumber()); |
| | | // TODO 加配置文件取 |
| | | cancelTaxiPassengerVo.setAppId(appid); |
| | | userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo); |
| | | |
| | | // 修改车辆接单状态 |
| | | vehicle.setState(0); |
| | | xpVehicleClient.updateVehicleById(vehicle); |
| | | } |
| | | |
| | | |
| | | // 根据订单所属开通城市id 查询定价 |
| | | R<XpPricing> pricingByCityId = xpPricingClient.getPricingByCid(order.getCityId()); |
| | |
| | | TaxiPricingDemoService.GpsPoint point = new TaxiPricingDemoService.GpsPoint(trajectory.getDistance(), trajectory.getLocatetime()); |
| | | gpsPoints.add(point); |
| | | } |
| | | // 补充临时轨迹数据 |
| | | // List<TaxiPricingDemoService.GpsPoint> gpsPoints = TaxiPricingDemoService.createMockGpsPoints(DateUtils.toDate(order.getCreateTime())); |
| | | |
| | | |
| | | TaxiPricingDemoService.PricingConfig config = new TaxiPricingDemoService.PricingConfig(); |
| | | JSONArray startingFareJsonArray = JSONArray.parseArray(pricing.getStartingFareJson()); |
| | |
| | | Double duration1 = order.getDuration(); |
| | | |
| | | com.alibaba.fastjson.JSONObject basicPricingJson = com.alibaba.fastjson.JSONObject.parseObject(pricing.getBasicPricingJson()); |
| | | // String num1 = "00:00"; |
| | | // String num2 = "23:59"; |
| | | // String num3 = basicPricingJson.getString("num1"); |
| | | // String num4 = basicPricingJson.getString("num2"); |
| | | // String num5 = basicPricingJson.getString("num3"); |
| | | // String num6 = basicPricingJson.getString("num4"); |
| | | // String num7 = basicPricingJson.getString("num5"); |
| | | // config.normals.add(new TaxiPricingDemoService.PricingRule("普通时段", num1, num2, Double.parseDouble(num3), Double.parseDouble(num4), Double.parseDouble(num5), Double.parseDouble(num6), Double.parseDouble(num7))); |
| | | // paramNum4 = basicPricingJson.getDouble("num2"); |
| | | // paramNum5 = basicPricingJson.getDouble("num3"); |
| | | |
| | | XpPricingCardVo xpPricingCardVo = xpPricingUtil.calculationFixedPrice(orderAppUserId.toString(), basicPricingJson, null, mileageKilometers, duration1, 0, 0.0, pricing.getIsDynamicPrice(), order.getCityId(), pricing.getDynamicPricingJson()); |
| | | XpOrderDetail xpOrderDetail = new XpOrderDetail(); |
| | | xpOrderDetail.setDetailType(1); |
| | |
| | | order.setOrderMoney(totalPrice); |
| | | order.setAppUserId(null); |
| | | baseMapper.updateById(order); |
| | | |
| | | |
| | | } else { |
| | | |
| | | |
| | | //动态计费 |
| | | if (pricing.getPricingType() == 1) { |
| | | |
| | |
| | | BigDecimal add = order.getDurationMoney().add(fareBreakdownDetailVo.getMoney()); |
| | | order.setDurationMoney(add); |
| | | } |
| | | // for (XpOrderDetail xpOrderDetail : xpOrderDetails) { |
| | | // if (xpOrderDetail.getDetailType() == 1) { |
| | | // order.setDurationType(xpOrderDetail.getType()); |
| | | // order.setDurationMoney(xpOrderDetail.getMoney()); |
| | | //// order.setDuration(Double.parseDouble(xpOrderDetail.getDuration() + "")); |
| | | // } else { |
| | | // order.setLongDistanceType(order.getDurationType()); |
| | | // order.setLongDistance(xpOrderDetail.getMileage().doubleValue()); |
| | | // order.setLongDistancemoney(xpOrderDetail.getMoney()); |
| | | // } |
| | | // |
| | | // } |
| | | |
| | | |
| | | BigDecimal orderMoney = startMoney.add(mileageMoney).add(order.getDurationMoney() != null ? order.getDurationMoney() : BigDecimal.ZERO) |
| | | .add(order.getLongDistancemoney() != null ? order.getLongDistancemoney() : BigDecimal.ZERO) |
| | |
| | | } |
| | | order.setAppUserId(null); |
| | | baseMapper.updateById(order); |
| | | |
| | | |
| | | // 结束后的车辆操作 |
| | | if (vehicle != null) { |
| | | // 修改车辆状态 |
| | | vehicle.setState(0); |
| | | //发送巡游订单 |
| | | addCruiseMission(vehicle, order); |
| | | // // 获取配置 根据配置判断是否该收车 如果是则找到收车点位进行收车操作 |
| | | // R<XpTaskRule> xpTaskRuleR = xpTaskRuleClient.queryDetail(); |
| | | // XpTaskRule xpTaskRule = xpTaskRuleR.getData(); |
| | | // |
| | | // // 生成新的巡游单子 回到最新巡游的初始起点位置 |
| | | // XpCruiseOrder xpCruiseOrders = xpCruiseOrderMapper.selectOne(new LambdaQueryWrapper<XpCruiseOrder>().eq(XpCruiseOrder::getVehicleId, vehicle.getId()).eq(XpCruiseOrder::getStatus, 2).orderByDesc(BaseModel::getCreateTime).last("limit 1")); |
| | | // int temp=0; |
| | | // if(xpCruiseOrders==null){ |
| | | // temp=1; |
| | | // //特殊情况 可能没有产生终止的订单 (到站点就被正常接单了)所以找正常订单 |
| | | // xpCruiseOrders=xpCruiseOrderMapper.selectOne(new LambdaQueryWrapper<XpCruiseOrder>().eq(XpCruiseOrder::getVehicleId, vehicle.getId()).eq(XpCruiseOrder::getStatus, 3).orderByDesc(BaseModel::getCreateTime).last("limit 1")); |
| | | // } |
| | | // XpCruiseOrder xpCruiseOrder = new XpCruiseOrder(); |
| | | // xpCruiseOrder.setVehicleId(vehicle.getId()); |
| | | // xpCruiseOrder.setFleetId(vehicle.getFleetId()); |
| | | // xpCruiseOrder.setVehicleVin(vehicle.getVehicleVin()); |
| | | // xpCruiseOrder.setOrderType(2); |
| | | // // 返程起点是当前正常订单的终点 |
| | | // xpCruiseOrder.setStartPointId(order.getEndPointId()); |
| | | // xpCruiseOrder.setStartPointName(order.getEndPointName()); |
| | | // xpCruiseOrder.setStartLon(order.getEndLon()); |
| | | // xpCruiseOrder.setStartLat(order.getEndLat()); |
| | | // |
| | | // // 完成的直接走终点 终止的走起点 |
| | | // if(temp==0){ |
| | | // xpCruiseOrder.setEndPointId(xpCruiseOrders.getStartPointId()); |
| | | // xpCruiseOrder.setEndPointName(xpCruiseOrders.getStartPointName()); |
| | | // xpCruiseOrder.setEndLon(xpCruiseOrders.getStartLon()); |
| | | // xpCruiseOrder.setEndLat(xpCruiseOrders.getStartLat()); |
| | | // }else { |
| | | // xpCruiseOrder.setEndPointId(xpCruiseOrders.getEndPointId()); |
| | | // xpCruiseOrder.setEndPointName(xpCruiseOrders.getEndPointName()); |
| | | // xpCruiseOrder.setEndLon(xpCruiseOrders.getEndLon()); |
| | | // xpCruiseOrder.setEndLat(xpCruiseOrders.getEndLat()); |
| | | // } |
| | | // |
| | | // |
| | | // xpCruiseOrder.setStatus(0); |
| | | // xpCruiseOrder.setLastOrderId(xpCruiseOrders.getId()); |
| | | // xpCruiseOrder.setCreateTime(LocalDateTime.now()); |
| | | // xpCruiseOrder.setId("XU"+ IdUtil.fastUUID()); |
| | | // |
| | | // // 判断当前时分秒是否大于收车时间 |
| | | // LocalTime vehicleCollectionTime = xpTaskRule.getVehicleCollectionTime(); |
| | | // if (vehicleCollectionTime.isBefore(LocalTime.now())) { |
| | | // vehicle.setOperatingStatus(3); |
| | | // //找到车辆的收车点位 更新终点点位 |
| | | // R<XpCruiseOrder> returnCruisePoint = xpCruisePlanClient.findReturnCruisePoint(xpCruiseOrder); |
| | | // xpCruiseOrder = returnCruisePoint.getData(); |
| | | // } |
| | | // xpVehicleClient.updateVehicleById(vehicle); |
| | | // |
| | | // xpCruiseOrderMapper.insert(xpCruiseOrder); |
| | | // |
| | | // |
| | | // R<XpPoint> xpPointR = xpPointClient.queryById(order.getEndPointId()); |
| | | // XpPoint data = xpPointR.getData(); |
| | | // //下发命令 |
| | | // // 添加自动结束行程定时任务job |
| | | // Map<String, ? extends Object> jobMaps = |
| | | // new ImmutableMap.Builder<String, String>(). |
| | | // put("id", xpCruiseOrder.getId()) |
| | | // .build(); |
| | | // QuartzManager.addJob( |
| | | // AddCruiseMissionJob.class, |
| | | // (AddCruiseMissionJob.name + xpCruiseOrder.getId()).toUpperCase(), |
| | | // TimeJobType.ADD_CRUISE_MISSION, |
| | | // DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(data.getParkingTimeLimit())), |
| | | // jobMaps |
| | | // ); |
| | | |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | |
| | | public void addCruiseMission(XpVehicle vehicle, XpOrder order) { |
| | | log.info("添加巡游订单 {}", vehicle.getPlateNumber()); |
| | | if (vehicle.getState() != 0 || vehicle.getOperatingStatus() != 1) { |
| | | log.info("添加巡游单失败,车辆状态限制 {}", vehicle.getState()); |
| | | return; |
| | |
| | | } |
| | | xpVehicleClient.updateVehicleById(vehicle); |
| | | } |
| | | |
| | | xpCruiseOrderMapper.insert(xpCruiseOrder); |
| | | |
| | | |
| | | R<XpPoint> xpPointR = xpPointClient.queryById(order.getEndPointId()); |
| | | XpPoint data = xpPointR.getData(); |
| | | //下发命令 |
| | | // 添加自动结束行程定时任务job |
| | | Map<String, ? extends Object> jobMaps = |
| | | new ImmutableMap.Builder<String, String>(). |
| | | put("id", xpCruiseOrder.getId() + "") |
| | | .build(); |
| | | QuartzManager.addJob( |
| | | AddCruiseMissionJob.class, |
| | | (AddCruiseMissionJob.name + xpCruiseOrder.getId()).toUpperCase(), |
| | | TimeJobType.ADD_CRUISE_MISSION, |
| | | DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(data.getParkingTimeLimit())), |
| | | jobMaps |
| | | ); |
| | | log.info("添加巡游单成功 {}", xpCruiseOrder.getId()); |
| | | //下发XUP巡游订单报文 |
| | | PushOrderDto pushOrderDto = new PushOrderDto(); |
| | | pushOrderDto.setVin(xpCruiseOrder.getVehicleVin()); |
| | | pushOrderDto.setOrderId("XU" + xpCruiseOrder.getId()); |
| | | pushOrderDto.setStartLatitude(xpCruiseOrder.getStartLat()); |
| | | pushOrderDto.setStartLongitude(xpCruiseOrder.getStartLon()); |
| | | pushOrderDto.setEndLatitude(xpCruiseOrder.getEndLat()); |
| | | pushOrderDto.setEndLongitude(xpCruiseOrder.getEndLon()); |
| | | pushOrderDto.setOrderType(OrderType.CRUISE_ORDER); |
| | | pushOrderDto.setStage(2); |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | log.info("下发XUP巡游订单报文成功"); |
| | | } |
| | | |
| | | |
| | |
| | | .targetValue(account) |
| | | .title(title) |
| | | .body(content) |
| | | .androidExtParameters(body) |
| | | // .androidExtParameters(body) |
| | | .androidNotificationChannel(channelIds) |
| | | .build(); |
| | | if(deviceType == 2){ |
| | |
| | | private String fleetName; |
| | | |
| | | @ApiModelProperty(value = "下次保养时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") |
| | | @JsonFormat(pattern = "yyyy年M月dd日",timezone = "GMT+8") |
| | | private LocalDate nextMaintenanceTime; |
| | | |
| | | @ApiModelProperty(value = "车辆经度") |