yanderong
2026-07-23 393c3178a7beeb39915aff302d9f30ca2b6e5247
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
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;
        }
    }
}