曾富康
2026-06-25 07f26b29ec4532349f8d05001d339d909422e401
DriverYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/api/DriverController.java
@@ -22,6 +22,7 @@
import com.stylefeng.guns.modular.system.model.*;
import com.stylefeng.guns.modular.system.model.vo.*;
import com.stylefeng.guns.modular.system.service.*;
import com.stylefeng.guns.modular.system.util.GeodesyUtil;
import com.stylefeng.guns.modular.system.util.ResultUtil;
import com.stylefeng.guns.modular.system.util.WeChatUtil;
import com.stylefeng.guns.modular.system.warpper.*;
@@ -131,6 +132,9 @@
    
    @Autowired
    private WeChatUtil weChatUtil;
    @Autowired
    private GeodesyUtil geodesyUtil;
    
    /**
     * 获取短信验证码
@@ -469,9 +473,171 @@
                return null;
            }).filter(Objects::nonNull).collect(Collectors.toList());
        }
//        addMockNearbyDrivers(collect);
        return ResultUtil.success(collect);
    }
    /**
     * 司机端首页订单热力图。
     * 热力图统计的是订单起点位置,不统计司机位置;订单坐标统一取 startLon/startLat。
     * radius 为前端传入的查询半径,单位公里;不传时默认查询 5 公里范围内的可接订单。
     * 返回结果只包含热力图必要字段,不返回订单ID、乘客信息、地址等敏感数据。
     */
    @ResponseBody
    @PostMapping("/base/driver/queryNearbyOrderHeatMap")
    @ApiOperation(value = "司机端首页订单热力图", tags = {"司机端-首页"}, notes = "热力图统计订单位置,不统计司机位置")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "司机当前位置经度", name = "lon", required = true, dataType = "String"),
            @ApiImplicitParam(value = "司机当前位置纬度", name = "lat", required = true, dataType = "String"),
            @ApiImplicitParam(value = "查询半径,单位公里,不传默认5公里", name = "radius", required = false, dataType = "String"),
            @ApiImplicitParam(value = "订单业务类型:1=专车,2=出租车,3=跨城,4/5=小件物流,不传查询全部", name = "type", required = false, dataType = "int")
    })
    public ResultUtil<Map<String, Object>> queryNearbyOrderHeatMap(String lon, String lat, String radius, Integer type) {
        try {
            if (ToolUtil.isEmpty(lon) || ToolUtil.isEmpty(lat)) {
                return ResultUtil.paranErr();
            }
            Double centerLon = Double.valueOf(lon);
            Double centerLat = Double.valueOf(lat);
            Double radiusKm = ToolUtil.isEmpty(radius) ? 5D : Double.valueOf(radius);
            if (radiusKm <= 0) {
                return ResultUtil.paranErr();
            }
            List<Map<String, Object>> points = new ArrayList<>();
            String centerLonLat = centerLon + "," + centerLat;
            if (type == null || type == 1) {
                List<OrderPrivateCar> privateCars = orderPrivateCarService.selectList(new EntityWrapper<OrderPrivateCar>()
                        .eq("state", 1).isNotNull("startLon").isNotNull("startLat"));
                addOrderHeatMapPoints(points, privateCars, centerLonLat, radiusKm, 1);
            }
            if (type == null || type == 2) {
                List<OrderTaxi> taxis = orderTaxiService.selectList(new EntityWrapper<OrderTaxi>()
                        .eq("state", 1).isNotNull("startLon").isNotNull("startLat"));
                addOrderHeatMapPoints(points, taxis, centerLonLat, radiusKm, 2);
            }
            if (type == null || type == 3) {
                List<OrderCrossCity> crossCities = orderCrossCityService.selectList(new EntityWrapper<OrderCrossCity>()
                        .eq("state", 1).isNotNull("startLon").isNotNull("startLat"));
                addOrderHeatMapPoints(points, crossCities, centerLonLat, radiusKm, 3);
            }
            if (type == null || type == 4 || type == 5) {
                Wrapper<OrderLogistics> wrapper = new EntityWrapper<OrderLogistics>()
                        .eq("state", 1).isNotNull("startLon").isNotNull("startLat");
                if (type != null) {
                    wrapper.eq("type", type);
                }
                List<OrderLogistics> logistics = orderLogisticsService.selectList(wrapper);
                addOrderHeatMapPoints(points, logistics, centerLonLat, radiusKm, null);
            }
            Map<String, Object> data = new HashMap<>();
//            addMockOrderHeatMapPoints(points);
            data.put("centerLon", centerLon);
            data.put("centerLat", centerLat);
            data.put("radius", radiusKm);
            data.put("total", points.size());
            data.put("points", points);
            return ResultUtil.success(data);
        } catch (NumberFormatException e) {
            return ResultUtil.paranErr();
        } catch (Exception e) {
            e.printStackTrace();
            return ResultUtil.runErr();
        }
    }
    /**
     * 将指定业务的订单转换为热力点,并按半径过滤。
     * 每个订单默认生成一个热力点,count=1;小件物流使用订单自身 type 区分 4/5。
     */
    private void addOrderHeatMapPoints(List<Map<String, Object>> points, List<?> orders, String centerLonLat, Double radiusKm, Integer fixedType) {
        if (ToolUtil.isEmpty(orders)) {
            return;
        }
        for (Object order : orders) {
            Double startLon = null;
            Double startLat = null;
            Integer orderType = fixedType;
            if (order instanceof OrderPrivateCar) {
                OrderPrivateCar orderPrivateCar = (OrderPrivateCar) order;
                startLon = orderPrivateCar.getStartLon();
                startLat = orderPrivateCar.getStartLat();
            } else if (order instanceof OrderTaxi) {
                OrderTaxi orderTaxi = (OrderTaxi) order;
                startLon = orderTaxi.getStartLon();
                startLat = orderTaxi.getStartLat();
            } else if (order instanceof OrderCrossCity) {
                OrderCrossCity orderCrossCity = (OrderCrossCity) order;
                startLon = orderCrossCity.getStartLon();
                startLat = orderCrossCity.getStartLat();
            } else if (order instanceof OrderLogistics) {
                OrderLogistics orderLogistics = (OrderLogistics) order;
                startLon = orderLogistics.getStartLon();
                startLat = orderLogistics.getStartLat();
                orderType = orderLogistics.getType();
            }
            if (startLon == null || startLat == null) {
                continue;
            }
            Map<String, Double> distance = geodesyUtil.getDistance(centerLonLat, startLon + "," + startLat);
            if (distance == null || distance.get("WGS84") == null || distance.get("WGS84") > radiusKm * 1000) {
                continue;
            }
            Map<String, Object> point = new HashMap<>();
            point.put("lon", startLon);
            point.put("lat", startLat);
            point.put("count", 1);
            point.put("type", orderType);
            points.add(point);
        }
    }
    /**
     * 测试用司机假数据:在 104.05,30.59 附近补充 5 个司机位置,便于前端联调地图展示。
     */
    private void addMockNearbyDrivers(List<Map<String, Object>> collect) {
        double[][] mockPositions = {
                {104.0500, 30.5900},
                {104.0512, 30.5908},
                {104.0489, 30.5894},
                {104.0520, 30.5886},
                {104.0495, 30.5915}
        };
        for (int i = 0; i < mockPositions.length; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("driverId", -1001 - i);
            map.put("name", "测试司机" + (i + 1));
            map.put("lot", mockPositions[i][0]);
            map.put("lat", mockPositions[i][1]);
            collect.add(map);
        }
    }
    /**
     * 测试用订单热力图假数据:在 104.05,30.59 附近补充 5 个订单热力点,便于前端联调热力图展示。
     */
    private void addMockOrderHeatMapPoints(List<Map<String, Object>> points) {
        double[][] mockPositions = {
                {104.0500, 30.5900},
                {104.0510, 30.5906},
                {104.0490, 30.5892},
                {104.0522, 30.5888},
                {104.0487, 30.5913}
        };
        for (int i = 0; i < mockPositions.length; i++) {
            Map<String, Object> point = new HashMap<>();
            point.put("lon", mockPositions[i][0]);
            point.put("lat", mockPositions[i][1]);
            point.put("count", 1);
            point.put("type", i + 1);
            points.add(point);
        }
    }
    @ResponseBody
    @PostMapping("/api/driver/queryOrderDataFromDriver")