“mitao”
2026-03-27 6b7d9d7cff3704e048ee09b32f49d3d6a2358847
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
package com.xiaopeng.pushMessage.controller;
 
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO;
import com.xiaopeng.api.dto.pushMessage.SendMessageDTO;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.order.XpTestOrderClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.order.XpTestOrder;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.constant.Constants;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.PushMessageTypeEnum;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.pushMessage.utils.MapMatchingUtil;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.powermock.core.ListMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
 
@Slf4j
@Api(tags = "订单推送轨迹接口")
@RestController
@RequestMapping("")
public class PushOrderRouteController {
 
    @Autowired
    private RedisService redisService;
    @Autowired
    private XpPushMessageClient xpPushMessageClient;
    @Autowired
    private XpOrderClient xpOrderClient;
 
    /**
     * 通过车辆实时位置
     * 给乘客端推送剩余轨迹和剩余里程时长
     * @return
     */
    @PostMapping("/inner/v1/order/pushOrderRoute")
    public R<String> pushOrderRoute(@Validated @RequestBody PushOrderRouteDTO dto) {
        Integer routeType = dto.getRouteType();
        //正常订单
        if(routeType == 1){
            XpOrder xpOrder = xpOrderClient.queryOrderById(dto.getOrderId()).getData();
            // 获取路线规划
            String key = "";
            //接驾情况,获取车辆位置到起点的导航
            if(xpOrder.getStatus() == 2 || xpOrder.getStatus() == 3){
                key = "ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId();
            }else{
                key = "ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId();
            }
            Object cacheObject = redisService.getCacheObject(key);
            RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class);
 
            if(Objects.nonNull(routeVo)){
                Integer distance = dto.getDistance();
                Integer duration = dto.getDuration();
                // 计算实时点位到线段的最优截取
                Map<String, List<LonLatDto>> remainingNavigation = MapMatchingUtil.getRemainingNavigation(routeVo.getPolyline(), dto.getLongitude(), dto.getLatitude());
                //当订单状态为5的时候(乘客已上车)需要推送导航的距离和剩余时间
                //因为这个状态,车端推的依然是接驾的剩余里程和时间,就会导致数据和小程序的页面跳转匹配不上
                //小程序是只要乘客上车后就跳转到行程开始页面
                if(5 != xpOrder.getStatus()){
                    routeVo.setDistance(distance);
                    routeVo.setDuration(duration);
                }else{
                    distance = routeVo.getDistance();
                    duration = routeVo.getDuration();
                }
                List<LonLatDto> lonLatDtos = remainingNavigation.get("unserved");
                List<LonLatDto> lonLatDtos1 = remainingNavigation.get("served");
                routeVo.setPolyline(lonLatDtos);
                routeVo.setServed(lonLatDtos1);
 
                // 存储最新路线偏离缓存,后续进行轨迹截取
                redisService.setCacheObject(key, JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
 
                // 封装轨迹点位集合
                List<Map<String, Object>> polyline = new ArrayList<>();
                for (LonLatDto lonLatDto : lonLatDtos) {
                    Map<String, Object> polylineMap = new HashMap<>();
                    polylineMap.put("longitude",lonLatDto.getLongitude());
                    polylineMap.put("latitude",lonLatDto.getLatitude());
                    polyline.add(polylineMap);
                }
                List<Map<String, Object>> served = new ArrayList<>();
                for (LonLatDto lonLatDto : lonLatDtos1) {
                    Map<String, Object> polylineMap = new HashMap<>();
                    polylineMap.put("longitude",lonLatDto.getLongitude());
                    polylineMap.put("latitude",lonLatDto.getLatitude());
                    served.add(polylineMap);
                }
                // 封装路由详情
                Map<String, Object> route = new HashMap<>();
                route.put("distance",distance);
                route.put("duration",duration);
                route.put("polyline",JSONObject.toJSONString(polyline));
                route.put("served",JSONObject.toJSONString(served));
 
                Map<String, Object> content = new HashMap<>();
                content.put("orderId",dto.getOrderId().toString());
                content.put("routeType",routeType);
                content.put("direction",dto.getDirection());
                content.put("route",JSONObject.toJSONString(route));
 
                // 封装轨迹信息
                Map<String, Object> params = new HashMap<>();
                params.put("type", PushMessageTypeEnum.ORDER_ROUTE.getDesc());
                params.put("content", JSONObject.toJSONString(content));
                params.put("timestamp", new Date().getTime()+"");
 
                // 进行消息推送
                SendMessageDTO sendMessageDTO = new SendMessageDTO();
                sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId()));
                sendMessageDTO.setMessage(JSONObject.toJSONString(params));
                R<String> stringR = xpPushMessageClient.sendRoute(sendMessageDTO);
                //推送失败,重试3次
                if(stringR.getCode() != Constants.SUCCESS){
                    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                    executor.execute(() -> {
                        for (int i = 0; i < 3; i++) {
                            R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                            if(stringR1.getCode() == Constants.SUCCESS){
                                break;
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            log.info("推送乘客端剩余导航数据消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), xpOrder.getOrderNumber());
                        }
                    });
                }
 
                log.info("推送剩余导航数据成功 {} {}", xpOrder.getOrderNumber(), JSON.toJSONString(routeVo));
            }
        }
        return R.ok();
    }
 
}