package com.stylefeng.guns.modular.api; import com.alibaba.fastjson.JSONObject; import com.stylefeng.guns.core.util.ToolUtil; import com.stylefeng.guns.modular.crossCity.model.OrderCrossCity; import com.stylefeng.guns.modular.crossCity.server.IOrderCrossCityService; import com.stylefeng.guns.modular.smallLogistics.model.OrderLogistics; import com.stylefeng.guns.modular.smallLogistics.server.IOrderLogisticsService; import com.stylefeng.guns.modular.specialTrain.model.OrderPrivateCar; import com.stylefeng.guns.modular.specialTrain.server.IOrderPrivateCarService; import com.stylefeng.guns.modular.system.util.GeodesyUtil; import com.stylefeng.guns.modular.system.util.PushUtil; import com.stylefeng.guns.modular.system.util.ResultUtil; import com.stylefeng.guns.modular.taxi.model.OrderTaxi; import com.stylefeng.guns.modular.taxi.service.IOrderTaxiService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.Map; import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/base/passenger/location") public class PassengerLocationController { @Autowired private IOrderPrivateCarService orderPrivateCarService; @Autowired private IOrderTaxiService orderTaxiService; @Autowired private IOrderCrossCityService orderCrossCityService; @Autowired private IOrderLogisticsService orderLogisticsService; @Autowired private PushUtil pushUtil; @Autowired private GeodesyUtil geodesyUtil; @Autowired private RestTemplate restTemplate; @Value("${qyt.management_uri:http://127.0.0.1:8010}") private String managementUri; @Resource private RedisTemplate redisTemplate; @ResponseBody @PostMapping("/push") public ResultUtil push(Integer userId, Integer orderId, Integer orderType, String lon, String lat, String timestamp) { try { // 校验乘客定位上报的必填参数 if (ToolUtil.isEmpty(userId) || ToolUtil.isEmpty(orderId) || ToolUtil.isEmpty(orderType) || ToolUtil.isEmpty(lon) || ToolUtil.isEmpty(lat)) { return ResultUtil.paranErr(); } Double lonValue; Double latValue; try { lonValue = Double.valueOf(lon); latValue = Double.valueOf(lat); } catch (NumberFormatException e) { return ResultUtil.paranErr(); } if (lonValue == 0 || latValue == 0) { return ResultUtil.paranErr(); } if (ToolUtil.isEmpty(timestamp)) { timestamp = String.valueOf(System.currentTimeMillis()); } if (!isSupportedOrderType(orderType)) { return ResultUtil.error("订单类型暂不支持"); } // 根据订单类型查询对应订单,并校验乘客、司机和订单状态 OrderData orderData = queryOrder(orderId, orderType); if (orderData == null) { return ResultUtil.error("订单不存在"); } if (!userId.equals(orderData.userId)) { return ResultUtil.error("用户与订单不匹配"); } if (ToolUtil.isEmpty(orderData.driverId) || orderData.driverId == 0) { return ResultUtil.error("订单暂无司机"); } if (!Integer.valueOf(3).equals(orderData.state)) { return ResultUtil.error("订单状态不是待到达预约地点"); } if (!validLonLat(orderData.startLon, orderData.startLat)) { return ResultUtil.error("订单上车点经纬度异常"); } if (exceedPassengerLocationDistance(orderData, lonValue, latValue)) { return ResultUtil.success("乘客距离上车点超过配置范围,未推送司机", new JSONObject()); } // 只缓存乘客最新位置,不记录历史轨迹 JSONObject location = new JSONObject(); location.put("orderId", orderId); location.put("orderType", orderType); location.put("userId", userId); location.put("driverId", orderData.driverId); location.put("lon", lon); location.put("lat", lat); location.put("timestamp", timestamp); redisTemplate.opsForValue().set("dache:PASSENGER_LOCATION:" + orderType + ":" + orderId, location.toJSONString(), 30, TimeUnit.SECONDS); // 缓存成功后实时推送给订单司机 return pushUtil.pushPassengerLocationToDriver(orderData.driverId, userId, orderId, orderType, lon, lat, timestamp); } catch (Exception e) { e.printStackTrace(); return ResultUtil.runErr(); } } private boolean isSupportedOrderType(Integer orderType) { return orderType == 1 || orderType == 2 || orderType == 3 || orderType == 4 || orderType == 5; } /** * 判断乘客当前位置是否超过企业配置的上车点距离阈值 */ private boolean exceedPassengerLocationDistance(OrderData orderData, Double lon, Double lat) { BigDecimal passengerLocationDistance = queryPassengerLocationDistance(orderData.companyId); if (passengerLocationDistance == null) { return false; } Map distance = geodesyUtil.getDistance(lon + "," + lat, orderData.startLon + "," + orderData.startLat); Double distanceMeter = distance == null ? null : distance.get("WGS84"); if (distanceMeter == null) { return false; } BigDecimal distanceKm = BigDecimal.valueOf(distanceMeter).divide(BigDecimal.valueOf(1000)); return distanceKm.compareTo(passengerLocationDistance) > 0; } /** * 远程查询企业乘客定位推送距离阈值,查询失败时不影响主流程 */ private BigDecimal queryPassengerLocationDistance(Integer companyId) { if (ToolUtil.isEmpty(companyId) || companyId == 0) { return null; } try { String result = restTemplate.postForObject(managementUri + "/base/distanceDisplay/passengerLocationDistance?companyId=" + companyId, null, String.class); JSONObject jsonObject = JSONObject.parseObject(result); if (jsonObject == null || jsonObject.getIntValue("code") != 200 || jsonObject.get("data") == null) { return null; } return jsonObject.getBigDecimal("data"); } catch (Exception e) { System.err.println("查询乘客定位推送距离阈值失败:" + e.getMessage()); return null; } } /** * 校验经纬度是否有效 */ private boolean validLonLat(Double lon, Double lat) { return lon != null && lat != null && lon != 0 && lat != 0; } /** * 根据订单类型查询对应订单的乘客、司机和状态 */ private OrderData queryOrder(Integer orderId, Integer orderType) { switch (orderType) { case 1: OrderPrivateCar orderPrivateCar = orderPrivateCarService.selectById(orderId); return orderPrivateCar == null ? null : new OrderData(orderPrivateCar.getUserId(), orderPrivateCar.getDriverId(), orderPrivateCar.getState(), orderPrivateCar.getCompanyId(), orderPrivateCar.getStartLon(), orderPrivateCar.getStartLat()); case 2: OrderTaxi orderTaxi = orderTaxiService.selectById(orderId); return orderTaxi == null ? null : new OrderData(orderTaxi.getUserId(), orderTaxi.getDriverId(), orderTaxi.getState(), orderTaxi.getCompanyId(), orderTaxi.getStartLon(), orderTaxi.getStartLat()); case 3: OrderCrossCity orderCrossCity = orderCrossCityService.selectById(orderId); return orderCrossCity == null ? null : new OrderData(orderCrossCity.getUserId(), orderCrossCity.getDriverId(), orderCrossCity.getState(), orderCrossCity.getCompanyId(), orderCrossCity.getStartLon(), orderCrossCity.getStartLat()); case 4: case 5: OrderLogistics orderLogistics = orderLogisticsService.selectById(orderId); return orderLogistics == null ? null : new OrderData(orderLogistics.getUserId(), orderLogistics.getDriverId(), orderLogistics.getState(), orderLogistics.getCompanyId(), orderLogistics.getStartLon(), orderLogistics.getStartLat()); default: return null; } } private static class OrderData { private final Integer userId; private final Integer driverId; private final Integer state; private final Integer companyId; private final Double startLon; private final Double startLat; private OrderData(Integer userId, Integer driverId, Integer state, Integer companyId, Double startLon, Double startLat) { this.userId = userId; this.driverId = driverId; this.state = state; this.companyId = companyId; this.startLon = startLon; this.startLat = startLat; } } }