| | |
| | | @ApiModelProperty(value = "消息类型") |
| | | private String messageType; |
| | | |
| | | @ApiModelProperty("连环单上一单的终点经度") |
| | | private Double endLongitude; |
| | | |
| | | @ApiModelProperty("连环单上一单的终点维度") |
| | | private Double endLatitude; |
| | | |
| | | } |
| | |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.operation.VehiclePositionVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleDoorStatusVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | |
| | | log.error("获取服务车辆列表失败,原因: {}", cause.getMessage()); |
| | | return R.fail("获取服务车辆列表失败:" + cause.getMessage()); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public R<VehicleDoorStatusVo> getVehicleDoorStatus(Long orderId) { |
| | | log.error("获取车辆四门三盖状态失败,原因: {}", cause.getMessage()); |
| | | return R.fail("获取车辆四门三盖状态失败:" + cause.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | import com.xiaopeng.api.dto.vehicleConvoy.UpdateVehicleStateDto; |
| | | import com.xiaopeng.api.factory.vehicleConvoy.XpVehicleClientFallbackFactory; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleDoorStatusVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | @PostMapping("/logan/inner/vehicle/getServiceVehicleList") |
| | | R<List<XpVehicle>> getServiceVehicleList(@RequestBody ServiceVehicleListDto dto); |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据订单id查询四门三盖状态 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @GetMapping("/logan/inner/vehicle/getVehicleDoorStatus/{orderId}") |
| | | R<VehicleDoorStatusVo> getVehicleDoorStatus(@PathVariable Long orderId); |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.api.vo.automaticPilot; |
| | | |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.data.mongodb.core.geo.GeoJsonPoint; |
| | | import org.springframework.data.mongodb.core.index.CompoundIndex; |
| | | import org.springframework.data.mongodb.core.index.CompoundIndexes; |
| | | import org.springframework.data.mongodb.core.index.GeoSpatialIndexType; |
| | | import org.springframework.data.mongodb.core.index.GeoSpatialIndexed; |
| | | import org.springframework.data.mongodb.core.mapping.Document; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * 车辆实时位置信息 |
| | | */ |
| | | @Data |
| | | @Document(collection = "app_user_position") |
| | | @CompoundIndexes({ |
| | | @CompoundIndex(name = "appUserId", def = "{'appUserId': 1}"), |
| | | @CompoundIndex(name = "location_index", def = "{'point': '2dsphere'}") |
| | | } |
| | | ) |
| | | public class AppUserPosition implements Serializable { |
| | | /** |
| | | * 用户id |
| | | */ |
| | | private Long appUserId; |
| | | /** |
| | | * 车辆实时位置信息 |
| | | */ |
| | | @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE) |
| | | private GeoJsonPoint point; |
| | | /** |
| | | * 添加时间 |
| | | */ |
| | | private Long addTime; |
| | | } |
| | |
| | | |
| | | @ApiModelProperty("被截取的点位,用于前端使用") |
| | | private List<LonLatDto> served; |
| | | |
| | | @ApiModelProperty("连环单上一单的终点经度") |
| | | private Double endLongitude; |
| | | |
| | | @ApiModelProperty("连环单上一单的终点维度") |
| | | private Double endLatitude; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.api.vo.vehicleConvoy; |
| | | |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class VehicleDoorStatusVo { |
| | | @ApiModelProperty("前左门状态(开=1/关=0)") |
| | | private Integer frontLeftDoor; |
| | | @ApiModelProperty("前右门状态(开=1/关=0)") |
| | | private Integer frontRightDoor; |
| | | @ApiModelProperty("后左门状态(开=1/关=0)") |
| | | private Integer rearLeftDoor; |
| | | @ApiModelProperty("后右门状态(开=1/关=0)") |
| | | private Integer rearRightDoor; |
| | | @ApiModelProperty("后备箱盖状态(开=1/关=0)") |
| | | private Integer trunk; |
| | | @ApiModelProperty("前备箱盖状态(开=1/关=0)") |
| | | private Integer frunk; |
| | | @ApiModelProperty("充电口盖状态(开=1/关=0)") |
| | | private Integer chargePort; |
| | | } |
| | |
| | | DOOR_TRUNK_CLOSE("DOOR_TRUNK_CLOSE", "后备箱关闭"), |
| | | DOOR_UNLOCK("DOOR_UNLOCK", "车门开锁"), |
| | | HVAC_TEMP_SET_FLOAT("HVAC_TEMP_SET_FLOAT", "设定温度"), |
| | | STATUS_REPORT_NOW("STATUS_REPORT_NOW", "上报实时车况"); |
| | | STATUS_REPORT_NOW("STATUS_REPORT_NOW", "上报实时车况"), |
| | | HVAC_ON("HVAC_ON", "空调开启"), |
| | | HVAC_OFF("HVAC_OFF", "空调关闭"); |
| | | /** |
| | | * 命令 |
| | | */ |
| | |
| | | if(!order_id.contains("TEST")){ |
| | | xpPushMessageClient.pushOrderRoute(dto);//存储历史轨迹 |
| | | // 给连环派单的用户推送 |
| | | Long nextOrderId = redisService.getCacheObject(CacheConstants.nextOrder(order_id)); |
| | | if (null != nextOrderId){ |
| | | dto.setOrderId(nextOrderId); |
| | | String json = redisService.getCacheObject(CacheConstants.nextOrder(order_id)); |
| | | if (StringUtils.isNotEmpty(json)){ |
| | | JSONObject jsonObject = JSON.parseObject(json); |
| | | dto.setOrderId(jsonObject.getLong("orderId")); |
| | | dto.setEndLongitude(jsonObject.getDouble("endLongitude")); |
| | | dto.setEndLatitude(jsonObject.getDouble("endLatitude")); |
| | | xpPushMessageClient.pushOrderRoute(dto); |
| | | } |
| | | xpOrderClient.saveVehicleLocation(orderTrajectory); |
| | |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.SEE_OFF_GUESTS.getCode(), true); |
| | | redisService.setCacheObject("ORDER_STATUS:" + orderId, OrderStatusEnum.SEE_OFF_GUESTS.getCode(), 24L, TimeUnit.HOURS); |
| | | // 判断当前订单的车辆是否有连环派单,然后判断是都还满足连环派单的条件,不满足则需要重新派单 |
| | | Long nextOrderId = redisService.getCacheObject(CacheConstants.nextOrder(orderId)); |
| | | if(null != nextOrderId){ |
| | | String json = redisService.getCacheObject(CacheConstants.nextOrder(orderId)); |
| | | if (StringUtils.isNotEmpty(json)){ |
| | | JSONObject jsonObject = JSON.parseObject(json); |
| | | Long nextOrderId = jsonObject.getLong("orderId"); |
| | | XpOrder nextOrder = xpOrderClient.queryOrderById(nextOrderId).getData(); |
| | | if(null != nextOrder && nextOrder.getStatus() == OrderStatusEnum.PICK_UP.getCode()){ |
| | | redisService.setCacheObject(CacheConstants.nextOrder(orderId),null); |
| | |
| | | if (!SmsType.ACCEPT_RIDES.name().equals(smsType)) { |
| | | return null; |
| | | } |
| | | // XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData(); |
| | | // if (vehicle == null) { |
| | | // return XpCommonResponse.fail(RobotaxiErrorEnum.MOBILE_VIN_MISMATCH); |
| | | // } |
| | | // Integer status = vehicle.getStatus(); |
| | | // Integer operatingStatus = vehicle.getOperatingStatus(); |
| | | // if (status == null || status != 2 || operatingStatus == null || operatingStatus != 1) { |
| | | // return XpCommonResponse.fail(RobotaxiErrorEnum.VEHICLE_NOT_READY); |
| | | // } |
| | | |
| | | XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData(); |
| | | if (vehicle == null) { |
| | | return XpCommonResponse.fail(RobotaxiErrorEnum.MOBILE_VIN_MISMATCH); |
| | | } |
| | | Integer status = vehicle.getStatus(); |
| | | Integer operatingStatus = vehicle.getOperatingStatus(); |
| | | if (smsType.equals(SmsType.ACCEPT_RIDES.name()) && operatingStatus != 1) { |
| | | return XpCommonResponse.fail(RobotaxiErrorEnum.VEHICLE_NOT_READY); |
| | | } |
| | | if (smsType.equals(SmsType.STOP_ACCEPT_RIDES.name()) && operatingStatus != 3) { |
| | | return XpCommonResponse.fail(RobotaxiErrorEnum.VEHICLE_NOT_READY); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.xiaopeng.api.dto.automaticPilot.PushOrderDto; |
| | | import com.xiaopeng.api.dto.operation.ReassignOrderDTO; |
| | | import com.xiaopeng.api.dto.order.OrderChangeDto; |
| | |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.OrderStatusEnum; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.core.utils.StringUtils; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.itinerary.constant.I18nKeyConstant; |
| | | import com.xiaopeng.itinerary.mapper.XpElectronicFenceAreaMapper; |
| | |
| | | |
| | | |
| | | // 判断当前订单的车辆是否有连环派单,然后判断是都还满足连环派单的条件,不满足则需要重新派单 |
| | | Long nextOrderId = redisService.getCacheObject(CacheConstants.nextOrder(order.getId().toString())); |
| | | if(null != nextOrderId){ |
| | | String json = redisService.getCacheObject(CacheConstants.nextOrder(order.getId().toString())); |
| | | if (StringUtils.isNotEmpty(json)){ |
| | | JSONObject jsonObject = JSON.parseObject(json); |
| | | Long nextOrderId = jsonObject.getLong("orderId"); |
| | | XpOrder nextOrder = xpOrderClient.queryOrderById(nextOrderId).getData(); |
| | | if(null != nextOrder && nextOrder.getStatus() == OrderStatusEnum.PICK_UP.getCode()){ |
| | | redisService.setCacheObject(CacheConstants.nextOrder(order.getId().toString()),null); |
| | |
| | | |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.xiaopeng.api.dto.automaticPilot.PushOrderDto; |
| | | import com.xiaopeng.api.dto.map.RouteAndFareDto; |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | |
| | | pushOrderDto.setTaskId(xpOrder.getXpuTaskId()); |
| | | // 订单流转 |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | redisService.setCacheObject(CacheConstants.nextOrder(luckyOder.getId().toString()), xpOrder.getId()); |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("orderId", xpOrder.getId()); |
| | | jsonObject.put("endLongitude", xpOrder.getEndLat()); |
| | | jsonObject.put("endLatitude", xpOrder.getEndLat()); |
| | | redisService.setCacheObject(CacheConstants.nextOrder(luckyOder.getId().toString()), jsonObject.toJSONString()); |
| | | redisService.setCacheObject(CacheConstants.navigationStart(xpOrder.getAppUserId().toString()), routeToOrigin); |
| | | redisService.removeByPattern(quoteName,xpOrder.getOrderNumber()); |
| | | log.info("将订单 {} 从队列 {} 弹出去", orderNo, quoteName); |
| | |
| | | pushOrderDto.setVin(xpVehicle.getVehicleVin()); |
| | | // 订单流转 |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | | redisService.setCacheObject(CacheConstants.nextOrder(luckyOder.getId().toString()), data.getId()); |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("orderId", data.getId()); |
| | | jsonObject.put("endLongitude", data.getEndLat()); |
| | | jsonObject.put("endLatitude", data.getEndLat()); |
| | | redisService.setCacheObject(CacheConstants.nextOrder(luckyOder.getId().toString()), jsonObject.toJSONString()); |
| | | redisService.setCacheObject(CacheConstants.navigationStart(data.getAppUserId().toString()), routeToOrigin); |
| | | break; |
| | | } |
| | |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.automaticPilot.AppUserPosition; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleDoorStatusVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.utils.StringUtils; |
| | | import com.xiaopeng.order.dto.UserOrderListDto; |
| | |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | |
| | | |
| | | |
| | | /** |
| | | * 8. 查询乘客位置 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @GetMapping("/getAppUserLocation/{orderId}") |
| | | @ApiOperation(value = "查询乘客位置", notes = "客服系统对接") |
| | | @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataType = "Long", paramType = "path") |
| | | public R<AppUserLocationVo> getAppUserLocation(@PathVariable Long orderId){ |
| | | XpOrder xpOrder = xpOrderService.getById(orderId); |
| | | if(null == xpOrder){ |
| | | return R.ok(); |
| | | } |
| | | AppUserLocationVo vo = new AppUserLocationVo(); |
| | | AppUserPosition userPosition = mongoTemplate.findOne(Query.query(Criteria.where("appUserId").is(xpOrder.getAppUserId())), AppUserPosition.class); |
| | | if(null != userPosition){ |
| | | vo.setPassengerLng(userPosition.getPoint().getX()); |
| | | vo.setPassengerLat(userPosition.getPoint().getY()); |
| | | return R.ok(vo); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 9. 根据 订单查询安全带及座椅传感器状态 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @GetMapping("/getVehicleSeatStatus/{orderId}") |
| | | @ApiOperation(value = "根据 订单查询安全带及座椅传感器状态", notes = "客服系统对接") |
| | | @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataType = "Long", paramType = "path") |
| | | public R<VehicleSeatStatusVo> getVehicleSeatStatus(@PathVariable Long orderId){ |
| | | XpOrder xpOrder = xpOrderService.getById(orderId); |
| | | if(null == xpOrder){ |
| | | return R.ok(); |
| | | } |
| | | |
| | | |
| | | |
| | | return R.ok(); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 10. 根据 VIN 查询剩余电量及预估续航 |
| | | * @param vin |
| | | * @return |
| | |
| | | vo.setEstimatedRange(Double.valueOf(vehiclePositions.getMileageRange())); |
| | | return R.ok(vo); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 11. 根据 订单查询四门三盖状态 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @GetMapping("/getVehicleDoorStatus/{orderId}") |
| | | @ApiOperation(value = "根据 订单查询四门三盖状态", notes = "客服系统对接") |
| | | @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataType = "Long", paramType = "path") |
| | | public R<VehicleDoorStatusVo> getVehicleDoorStatus(@PathVariable Long orderId){ |
| | | VehicleDoorStatusVo data = xpVehicleClient.getVehicleDoorStatus(orderId).getData(); |
| | | return R.ok(data); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 12. 根据 订单查询车辆位置及电子围栏信息 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @GetMapping("/getVehicleFenceInformation/{orderId}") |
| | | @ApiOperation(value = "根据 订单查询车辆位置及电子围栏信息", notes = "客服系统对接") |
| | | @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataType = "Long", paramType = "path") |
| | | public R<VehicleFenceInformationVo> getVehicleFenceInformation(@PathVariable Long orderId){ |
| | | XpOrder xpOrder = xpOrderService.getById(orderId); |
| | | if(null == xpOrder){ |
| | | return R.ok(); |
| | | } |
| | | XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); |
| | | VehiclePosition vehiclePositions = mongoTemplate.findOne(Query.query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class); |
| | | if(null == vehiclePositions){ |
| | | return R.ok(); |
| | | } |
| | | VehicleFenceInformationVo vo = new VehicleFenceInformationVo(); |
| | | vo.setVehicleLng(vehiclePositions.getPoint().getX()); |
| | | vo.setVehicleLat(vehiclePositions.getPoint().getY()); |
| | | vo.setGeofenceBoundary(new ArrayList<>()); |
| | | vo.setIsOutOfGeofence(false); |
| | | return R.ok(vo); |
| | | } |
| | | } |
| | |
| | | XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); |
| | | VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class); |
| | | routeVo.setDirection(null != vehiclePosition ? vehiclePosition.getCourse() : 90); |
| | | |
| | | Long vehicleId = xpOrder.getVehicleId(); |
| | | XpOrder one = xpOrderService.getOne(new QueryWrapper<XpOrder>().eq("vehicle_id", vehicleId).in("status", Arrays.asList(6, 7)).eq("is_deleted", 0)); |
| | | if(null != one){ |
| | | routeVo.setEndLongitude(one.getEndLon()); |
| | | routeVo.setEndLatitude(one.getEndLat()); |
| | | } |
| | | |
| | | return R.ok(routeVo); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | //判断是否有连环单 |
| | | Long id = redisService.getCacheObject(CacheConstants.nextOrder(xpOrder.getId().toString())); |
| | | if(id != null){ |
| | | String json = redisService.getCacheObject(CacheConstants.nextOrder(xpOrder.getId().toString())); |
| | | if (StringUtils.isNotEmpty(json)){ |
| | | JSONObject jsonObject = JSON.parseObject(json); |
| | | Long id = jsonObject.getLong("orderId"); |
| | | QuartzManager.addJob( |
| | | PushChainReactionOrderJob.class, |
| | | (PushChainReactionOrderJob.name + id).toUpperCase(), |
| New file |
| | |
| | | package com.xiaopeng.order.vo; |
| | | |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class AppUserLocationVo { |
| | | @ApiModelProperty("经度") |
| | | private Double passengerLng; |
| | | @ApiModelProperty("纬度") |
| | | private Double passengerLat; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.order.vo; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class FenceVo { |
| | | @ApiModelProperty("经度") |
| | | private Double lng; |
| | | @ApiModelProperty("纬度") |
| | | private Double lat; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.order.vo; |
| | | |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class VehicleFenceInformationVo { |
| | | @ApiModelProperty("车辆经度") |
| | | private Double vehicleLng; |
| | | @ApiModelProperty("车辆纬度") |
| | | private Double vehicleLat; |
| | | @ApiModelProperty("电子围栏经纬度数组") |
| | | private List<FenceVo> geofenceBoundary; |
| | | @ApiModelProperty("是否超越电子围栏边界") |
| | | private Boolean isOutOfGeofence; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.order.vo; |
| | | |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class VehicleSeatStatusVo { |
| | | @ApiModelProperty("主驾") |
| | | private String frontLeft; |
| | | @ApiModelProperty("副驾") |
| | | private String frontRight; |
| | | @ApiModelProperty("左后") |
| | | private String rearLeft; |
| | | @ApiModelProperty("右后") |
| | | private String rearRight; |
| | | } |
| | |
| | | content.put("routeType",routeType); |
| | | content.put("direction",dto.getDirection()); |
| | | content.put("route",JSONObject.toJSONString(route)); |
| | | content.put("endLongitude", dto.getEndLongitude()); |
| | | content.put("endLatitude", dto.getEndLatitude()); |
| | | |
| | | // 封装轨迹信息 |
| | | Map<String, Object> params = new HashMap<>(); |
| | |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.xiaopeng.api.vo.automaticPilot.AppUserPosition; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.pushMessage.webSocket.service.WebSocketUserConnectionManager; |
| | | import io.netty.channel.ChannelHandler; |
| | | import io.netty.channel.ChannelHandlerContext; |
| | |
| | | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.mongodb.core.MongoTemplate; |
| | | import org.springframework.data.mongodb.core.geo.GeoJsonPoint; |
| | | import org.springframework.data.mongodb.core.query.Criteria; |
| | | import org.springframework.data.mongodb.core.query.Query; |
| | | import org.springframework.data.mongodb.core.query.Update; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | | import java.util.function.Function; |
| | |
| | | |
| | | @Autowired |
| | | private WebSocketAuthHandler authHandler; |
| | | |
| | | @Resource |
| | | private MongoTemplate mongoTemplate; |
| | | |
| | | Map<String, BusinessMsgHandler> businessMsgHandlers; |
| | | |
| | |
| | | log.info("收到用户 {} 的实时位置消息: {}", appUserId, messageObj.toJSONString()); |
| | | Double latitude = messageObj.getDouble("latitude"); |
| | | Double longitude = messageObj.getDouble("longitude"); |
| | | String timestamp = messageObj.getString("timestamp"); |
| | | |
| | | saveAppUserLocation(Long.parseLong(appUserId), latitude, longitude); |
| | | } |
| | | |
| | | // 回复消息 |
| | |
| | | log.error("WebSocket连接异常: {}", cause.getMessage(), cause); |
| | | ctx.channel().close(); |
| | | } |
| | | |
| | | |
| | | |
| | | private void saveAppUserLocation(Long appUserId, Double latitude, Double longitude) { |
| | | AppUserPosition userPosition = mongoTemplate.findOne(Query.query(Criteria.where("appUserId").is(appUserId)), AppUserPosition.class); |
| | | GeoJsonPoint point = new GeoJsonPoint(longitude, latitude); |
| | | if(null != userPosition){ |
| | | mongoTemplate.updateFirst(Query.query(Criteria.where("appUserId").is(appUserId)), |
| | | Update.update("point", point).set("addTime", System.currentTimeMillis()), AppUserPosition.class); |
| | | }else{ |
| | | userPosition = new AppUserPosition(); |
| | | userPosition.setAppUserId(appUserId); |
| | | userPosition.setPoint(point); |
| | | userPosition.setAddTime(System.currentTimeMillis()); |
| | | mongoTemplate.save(userPosition); |
| | | } |
| | | } |
| | | } |
| | |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleStateVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.CarControlCallbackDTO; |
| | | import com.xiaopeng.vehicleConvoy.service.AsyncVehicleStateService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import javax.annotation.Resource; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * 控车回调接口 |
| | |
| | | |
| | | @Resource |
| | | private AsyncVehicleStateService asyncVehicleStateService; |
| | | private RedisService redisService; |
| | | |
| | | /** |
| | | * 车控指令执行的回调接口 |
| | |
| | | // 通知异步服务处理回调 |
| | | asyncVehicleStateService.handleStateCallback(request.getMsgRef(), stateData); |
| | | } |
| | | // 尝试解析车辆空调数据 |
| | | parseAirConditioningSwitchFromCallback(request); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("处理车辆状态回调异常: msgId={}", request.getMsgRef(), e); |
| | |
| | | // 解析door信息 |
| | | Map<String, Object> door = (Map<String, Object>) instant.get("door"); |
| | | if (door != null) { |
| | | //存入缓存用于后续使用 |
| | | redisService.setCacheObject("DOOR:" + callback.getMsgId(), JSON.toJSONString(door), 30L, TimeUnit.SECONDS); |
| | | // 获取trunk_ajar_st_new值 |
| | | Object trunkAjarStNewObj = door.get("trunk_ajar_st_new"); |
| | | if (trunkAjarStNewObj != null) { |
| | |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 从回调消息中解析车辆空调状态数据 |
| | | */ |
| | | private VehicleTemperatureDto parseAirConditioningSwitchFromCallback(CarControlCallbackDTO callback) { |
| | | try { |
| | | if (callback.getMsgContent() == null) { |
| | | return null; |
| | | } |
| | | |
| | | log.debug("解析空调状态数据: msgId={}, content={}", callback.getMsgRef(), JSON.toJSONString(callback.getMsgContent())); |
| | | |
| | | // 解析msgContent为Map结构 |
| | | Map<String, Object> msgContent = (Map<String, Object>) callback.getMsgContent(); |
| | | |
| | | // 检查返回码 |
| | | Integer code = (Integer) msgContent.get("code"); |
| | | if (code == null || code != 200) { |
| | | log.warn("空调状态回调返回错误码: msgId={}, code={}", callback.getMsgRef(), code); |
| | | return null; |
| | | } |
| | | |
| | | // 获取instant数据 |
| | | Map<String, Object> instant = (Map<String, Object>) msgContent.get("instant"); |
| | | if (instant == null) { |
| | | log.warn("回调数据中缺少instant字段: msgId={}", callback.getMsgRef()); |
| | | return null; |
| | | } |
| | | |
| | | // 创建VehicleTemperatureDto对象 |
| | | VehicleTemperatureDto stateData = new VehicleTemperatureDto(); |
| | | Map<String, VehicleStateVo> stateMap = new HashMap<>(); |
| | | |
| | | // 解析hvac信息 |
| | | Map<String, Object> hvac = (Map<String, Object>) instant.get("hvac"); |
| | | if (hvac != null) { |
| | | log.info("解析到空调: msgId={}, hvac_on={}", callback.getMsgRef(), JSON.toJSONString(hvac)); |
| | | //存入缓存用于后续使用 |
| | | redisService.setCacheObject("HVAC:" + callback.getMsgId(), JSON.toJSONString(hvac), 30L, TimeUnit.SECONDS); |
| | | } |
| | | stateData.setStateMap(stateMap); |
| | | return stateData; |
| | | } catch (Exception e) { |
| | | log.warn("解析空调状态数据失败: msgId={}", callback.getMsgRef(), e); |
| | | return null; |
| | | } |
| | | } |
| | | } |
| | |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicleAnnualRecord; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleDoorStatusVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleStateVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandCallbackVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | |
| | | XpOperationsUser xpOperationsUser = tokenService.getLoginOperationUser().getXpOperationsUser(); |
| | | return R.ok(xpVehicleService.unlockDoor(dto, xpOperationsUser)); |
| | | } |
| | | |
| | | |
| | | |
| | | @ApiOperation(value = "通过订单id查询当前车辆空调状态", tags = {"小程序-业务流程"}) |
| | | @GetMapping("/api/v1/mini-program/order/queryVehicleAirConditionerSwitch") |
| | | @XpClientCheck(checkToken = false, checkOtpToken = true) |
| | | public R<Boolean> queryVehicleAirConditionerSwitch(@RequestParam Long orderId, HttpServletRequest request) { |
| | | String uid = request.getHeader("XP-Uid"); |
| | | Boolean hasKey = xpVehicleService.queryVehicleAirConditionerSwitch(orderId, uid); |
| | | return R.ok(hasKey); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 业务流程-车门解锁/后备箱解锁 |
| | | */ |
| | | @ApiOperation(value = "打开/关闭车内空调", tags = {"小程序-业务流程"}) |
| | | @PostMapping("/api/v1/mini-program/order/airConditionerUnlock") |
| | | @XpClientCheck(checkToken = false, checkOtpToken = true) |
| | | public R<Integer> airConditionerUnlock(@RequestBody AirConditionerUnlockDTO dto, HttpServletRequest request) { |
| | | String uid = request.getHeader("XP-Uid"); |
| | | return R.ok(xpVehicleService.airConditionerUnlock(dto, uid)); |
| | | } |
| | | |
| | | /** |
| | | * 根据订单id查询四门三盖状态 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @GetMapping("/logan/inner/vehicle/getVehicleDoorStatus/{orderId}") |
| | | public R<VehicleDoorStatusVo> getVehicleDoorStatus(@PathVariable Long orderId){ |
| | | VehicleDoorStatusVo vehicleDoorStatus = xpVehicleService.getVehicleDoorStatus(orderId); |
| | | return R.ok(vehicleDoorStatus); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class AirConditionerUnlockDTO { |
| | | |
| | | @ApiModelProperty(value = "订单id") |
| | | private Long orderId; |
| | | |
| | | @ApiModelProperty(value = "开关控制(开=true, 关=false)") |
| | | private Boolean open; |
| | | } |
| | |
| | | import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleDoorStatusVo; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.*; |
| | | import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel; |
| | | import com.xiaopeng.vehicleConvoy.model.query.*; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | |
| | | * @return |
| | | */ |
| | | Integer unlockDoor(UnlockAppDTO dto, XpOperationsUser xpOperationsUser); |
| | | |
| | | |
| | | /** |
| | | * 根据订单id获取空调开关状态 |
| | | * @param orderId |
| | | * @param uid |
| | | * @return |
| | | */ |
| | | Boolean queryVehicleAirConditionerSwitch(Long orderId, String uid); |
| | | |
| | | |
| | | /** |
| | | * 开关空调 |
| | | * @param dto |
| | | * @param uid |
| | | * @return |
| | | */ |
| | | Integer airConditionerUnlock(AirConditionerUnlockDTO dto, String uid); |
| | | |
| | | |
| | | /** |
| | | * 获取车辆车门和后备箱状态 |
| | | * @param vehicleId |
| | | * @return |
| | | */ |
| | | VehicleDoorStatusVo getVehicleDoorStatus(Long orderId); |
| | | } |
| | |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.lang.Validator; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.core.exception.base.BaseException; |
| | | import com.xiaopeng.common.core.utils.GeodesyUtil; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | |
| | | import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel; |
| | | import com.xiaopeng.vehicleConvoy.model.query.*; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO; |
| | | import com.xiaopeng.vehicleConvoy.service.AsyncVehicleStateService; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpVehicleService; |
| | |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.*; |
| | | import java.util.concurrent.CompletableFuture; |
| | | import java.util.regex.Pattern; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | |
| | | @Resource |
| | | private UserResourcesClient userResourcesClient; |
| | | @Resource |
| | | private AsyncVehicleStateService asyncVehicleStateService; |
| | | |
| | | @Value("${vehicle.control.distance-threshold:100}") |
| | | private int distanceThreshold; |
| | |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 根据订单id获取空调开关状态 |
| | | * @param orderId |
| | | * @param uid |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Boolean queryVehicleAirConditionerSwitch(Long orderId, String uid) { |
| | | XpOrder xpOrder = xpOrderClient.queryOrderById(orderId).getData(); |
| | | if(null == xpOrder){ |
| | | return false; |
| | | } |
| | | XpVehicle vehicle = this.getById(xpOrder.getVehicleId()); |
| | | String vin = vehicle.getVehicleVin(); |
| | | // 1. 创建车辆控制指令 |
| | | VehiclesCommandVo commandVo = new VehiclesCommandVo(); |
| | | commandVo.setVin(vin); |
| | | commandVo.setCommandCode(VehiclesCommandEnum.STATUS_REPORT_NOW.getCommand()); |
| | | |
| | | // 2. 下发指令获取消息ID |
| | | String msgId = vehicleControlUtil.vehiclesCommand(commandVo, Long.valueOf(uid)); |
| | | if (StrUtil.isEmpty(msgId)) { |
| | | throw new BaseException("获取消息ID失败: " + msgId); |
| | | } |
| | | log.info("同步查询车辆空调状态成功,开始等到查询回调结果"); |
| | | try { |
| | | Thread.sleep(2000); |
| | | } catch (InterruptedException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | String cacheObject = redisService.getCacheObject("HVAC:" + msgId); |
| | | if(StringUtils.isEmpty(cacheObject)){ |
| | | return false; |
| | | } |
| | | JSONObject jsonObject = JSON.parseObject(cacheObject); |
| | | Integer hvac_on = jsonObject.getInteger("hvac_on"); |
| | | return hvac_on == 1; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 开关空调 |
| | | * @param dto |
| | | * @param uid |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Integer airConditionerUnlock(AirConditionerUnlockDTO dto, String uid) { |
| | | XpOrder xpOrder = xpOrderClient.queryOrderById(dto.getOrderId()).getData(); |
| | | if(null == xpOrder){ |
| | | return 0; |
| | | } |
| | | XpVehicle vehicle = this.getById(xpOrder.getVehicleId()); |
| | | VehiclesCommandVo vehiclesCommandVo = new VehiclesCommandVo(); |
| | | vehiclesCommandVo.setVin(vehicle.getVehicleVin()); |
| | | vehiclesCommandVo.setCommandCode(dto.getOpen() ? VehiclesCommandEnum.HVAC_ON.getCommand() : VehiclesCommandEnum.HVAC_OFF.getCommand()); |
| | | String msgId = vehicleControlUtil.vehiclesCommand(vehiclesCommandVo, Long.valueOf(uid)); |
| | | log.info("空调控制结果:{}", msgId); |
| | | if (StringUtils.isEmpty(msgId)) { |
| | | return 0; |
| | | } else { |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取车辆门锁状态 |
| | | * @param orderId |
| | | * @return |
| | | */ |
| | | @Override |
| | | public VehicleDoorStatusVo getVehicleDoorStatus(Long orderId) { |
| | | XpOrder xpOrder = xpOrderClient.queryOrderById(orderId).getData(); |
| | | if(null == xpOrder){ |
| | | return null; |
| | | } |
| | | XpVehicle vehicle = this.getById(xpOrder.getVehicleId()); |
| | | String vin = vehicle.getVehicleVin(); |
| | | // 1. 创建车辆控制指令 |
| | | VehiclesCommandVo commandVo = new VehiclesCommandVo(); |
| | | commandVo.setVin(vin); |
| | | commandVo.setCommandCode(VehiclesCommandEnum.STATUS_REPORT_NOW.getCommand()); |
| | | |
| | | // 2. 下发指令获取消息ID |
| | | String msgId = vehicleControlUtil.vehiclesCommand(commandVo, xpOrder.getAppUserId()); |
| | | if (StrUtil.isEmpty(msgId)) { |
| | | throw new BaseException("获取消息ID失败: " + msgId); |
| | | } |
| | | log.info("同步查询车辆空调状态成功,开始等到查询回调结果"); |
| | | try { |
| | | Thread.sleep(2000); |
| | | } catch (InterruptedException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | String cacheObject = redisService.getCacheObject("DOOR:" + msgId); |
| | | if(StringUtils.isEmpty(cacheObject)){ |
| | | return null; |
| | | } |
| | | // todo 待文档补充后再更新代码 |
| | | VehicleDoorStatusVo vo = new VehicleDoorStatusVo(); |
| | | JSONObject jsonObject = JSON.parseObject(cacheObject); |
| | | Integer driver_door_ajar_st = jsonObject.getInteger("driver_door_ajar_st"); |
| | | Integer passenger_door_ajar_st = jsonObject.getInteger("passenger_door_ajar_st"); |
| | | Integer rear_left_door_ajar_st = jsonObject.getInteger("rear_left_door_ajar_st"); |
| | | Integer rear_right_door_ajar_st = jsonObject.getInteger("rear_right_door_ajar_st"); |
| | | Integer trunk_ajar_st_new = jsonObject.getInteger("trunk_ajar_st_new"); |
| | | vo.setTrunk(trunk_ajar_st_new == 5 ? 1 : 0); |
| | | return vo; |
| | | } |
| | | } |