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<String, Object> 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<String, Double> 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;
|
}
|
}
|
}
|