liujie
2026-02-14 3bb68de5e58ec0935061ac7e143ee9d818b8c449
点位修改
2个文件已添加
6个文件已修改
797 ■■■■■ 已修改文件
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/map/PointByIpVo.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/IndexController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceAreaServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/AmapWalkingRouteUtil.java 606 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/GaodeMapService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TimeRangeChecker.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/map/PointByIpVo.java
New file
@@ -0,0 +1,15 @@
package com.xiaopeng.api.vo.map;
import com.xiaopeng.api.dto.operation.LonLatDto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel("根据ip获取点位")
public class PointByIpVo {
    private LonLatDto point;
    private String city;
    private String adcode;
}
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/IndexController.java
@@ -1,5 +1,6 @@
package com.xiaopeng.map.controller;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.dto.operation.PointMapQuery;
import com.xiaopeng.api.feignClient.operation.XpPointClient;
import com.xiaopeng.api.model.operation.XpPoint;
@@ -8,6 +9,7 @@
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.common.security.service.TokenService;
import com.xiaopeng.map.utils.AmapWalkingRouteUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@@ -15,6 +17,8 @@
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
/**
@@ -30,6 +34,7 @@
    private TokenService tokenService;
    @Autowired
    private XpPointClient pointClient;
    @ApiOperation(value = "地图导航")
    @PostMapping("/api/v1/map")
    public R<List<XpPoint>> pointMap(@RequestBody PointMapQuery query) {
@@ -51,7 +56,6 @@
        return pointClient.queryById(id);
    }
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java
@@ -4,6 +4,7 @@
import com.xiaopeng.api.dto.map.OrderRouteAndFareDto;
import com.xiaopeng.api.dto.map.RouteAndFareDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.vo.map.PointByIpVo;
import com.xiaopeng.api.vo.map.XpDistanceAndDurationVo;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.common.core.constant.CacheConstants;
@@ -11,17 +12,18 @@
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.map.mangodb.model.GeoPoint;
import com.xiaopeng.map.mangodb.service.XpGeoFencingPolygonService;
import com.xiaopeng.map.utils.AmapWalkingRouteUtil;
import com.xiaopeng.map.utils.GDMapGeocodingUtil;
import com.xiaopeng.map.utils.mangoUtils.MongoGeoFenceUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
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 org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -119,4 +121,16 @@
    /**
     * 根据ip获取点位
     */
    @ApiOperation(value = "根据ip获取点位", tags = {"小程序-站点导航"})
    @GetMapping("/point/getPointByIp")
    public R<PointByIpVo> getPointByIp(HttpServletRequest request) throws IOException {
        String ip = request.getRemoteAddr();
        PointByIpVo pointByIpVo = AmapWalkingRouteUtil.ipLocation(ip);
        return R.ok(pointByIpVo);
    }
}
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceAreaServiceImpl.java
@@ -279,9 +279,8 @@
    @Override
    public WalkTimeVo getWalkTime(WalkTimeDto dto) {
        WalkTimeVo walkTimeVo = new WalkTimeVo();
        String apiKey = "66ae577f63898dae3016d599fda57221";
        // 创建服务实例
        GaodeMapService gaodeService = new GaodeMapService(apiKey);
        GaodeMapService gaodeService = new GaodeMapService();
        AmapWalkingRouteUtil.WalkingRouteResult result = gaodeService.getWalkingRoute(dto.getStartLongitude()+","+dto.getStartLatitude(),dto.getEndLongitude()+","+dto.getEndLatitude());
        if (result.isSuccess()) {
            System.out.println("预计时间: " + result.getFormattedDuration());
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/AmapWalkingRouteUtil.java
@@ -1,18 +1,21 @@
package com.xiaopeng.map.utils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.vo.map.PointByIpVo;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.HttpUtils;
import com.xiaopeng.map.constant.I18nKeyConstant;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -26,317 +29,406 @@
    // 高德地图Web服务API配置
    private static final String AMAP_API_BASE_URL = "https://restapi.amap.com/v3/direction/walking";
    private static final String AMAP_GEOCODING_URL = "https://restapi.amap.com/v3/geocode/geo";
    // 高德API基础URL
    private static final String IP_API_URL = "https://restapi.amap.com/v3/ip";
    private static final String GEOCODE_API_URL = "https://restapi.amap.com/v3/geocode/geo";
    // 你的高德地图API Key(请替换成你自己的)
    private final String apiKey;
    // HTTP客户端
    private final OkHttpClient httpClient;
    private final ObjectMapper objectMapper;
    //    @Value("${map.apikey}")
    private static String apiKey="66ae577f63898dae3016d599fda57221";
    /**
     * 构造函数
     * @param apiKey 高德地图API Key
     * IP定位
     */
    public static PointByIpVo ipLocation(String ip) throws IOException {
        PointByIpVo pointByIpVo = new PointByIpVo();
        StringBuilder urlBuilder = new StringBuilder(IP_API_URL)
                .append("?key=").append(apiKey)
                .append("&output=json");
        if (ip != null && !ip.trim().isEmpty()) {
            urlBuilder.append("&ip=").append(ip);
        }
        String response = HttpUtils.sendGet(urlBuilder.toString());
        JSONObject jsonObject = JSONObject.parseObject(response);
        // 城市名称
        String city = jsonObject.getString("city");
        String province = jsonObject.getString("province");
        if(("局域网").equals(province)){
            pointByIpVo.setCity("成都市");
            LonLatDto lonLatDto = new LonLatDto(104.07, 30.660);
            pointByIpVo.setPoint(lonLatDto);
            pointByIpVo.setAdcode("510100");
            return pointByIpVo;
        }
        String adcode = jsonObject.getString("adcode");
        if (city == null || city.trim().isEmpty() || "[]".equals(city)) {
            // 直辖市:adcode前两位是11,12,31,50
            if (adcode != null) {
                String prefix = adcode.substring(0, 2);
                if ("11".equals(prefix)) {
                    city = "北京市";
                }
                if ("12".equals(prefix)) {
                    city = "天津市";
                }
                if ("31".equals(prefix)) {
                    city = "上海市";
                }
                if ("50".equals(prefix)) {
                    city = "重庆市";
                }
                // 如果没有city但有province,使用省份
                city = province;
            }
        }
        LonLatDto lonLatDto = geocodeCity(city);
        pointByIpVo.setCity(city);
        pointByIpVo.setPoint(lonLatDto);
        pointByIpVo.setAdcode(adcode);
        return pointByIpVo;
    }
    private static LonLatDto geocodeCity(String cityName) throws IOException {
        String url = GEOCODE_API_URL + "?key=" +apiKey + "&address=" + cityName + "&output=json&city=" + cityName;
        String response = HttpUtils.sendGet(url);
        System.out.println(response);
        JSONObject jsonObject = JSONObject.parseObject(response);
        // 获取geocodes数组
        JSONArray geocodes = jsonObject.getJSONArray("geocodes");
        if (geocodes == null || geocodes.isEmpty()) {
            return null;
        }
        // 取第一个geocode
        JSONObject firstGeocode = geocodes.getJSONObject(0);
        // 获取location字段
        String lonLat = firstGeocode.getString("location");
        String[] lonLatArray = lonLat.split(",");
        double longitude = Double.parseDouble(lonLatArray[0]);
        double latitude = Double.parseDouble(lonLatArray[1]);
        return new LonLatDto(longitude, latitude);
    }
        public static void main (String[]args) throws IOException {
            geocodeCity("凉山彝族自治州");
        }
        /**
         * 构造函数
         * @param apiKey 高德地图API Key
         */
    public AmapWalkingRouteUtil(String apiKey) {
        this.apiKey = apiKey;
        this.httpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .build();
        this.objectMapper = new ObjectMapper();
    }
    /**
     * 位置坐标类
     */
    public static class Location {
        private final double longitude; // 经度
        private final double latitude;  // 纬度
        public Location(double longitude, double latitude) {
            this.longitude = longitude;
            this.latitude = latitude;
        }
        public double getLongitude() {
            return longitude;
        }
        public double getLatitude() {
            return latitude;
        }
        @Override
        public String toString() {
            return String.format("%.6f,%.6f", longitude, latitude);
        }
    }
    /**
     * 步行路线结果类
     */
    public static class WalkingRouteResult {
        private int duration;      // 步行时间(秒)
        private int distance;      // 步行距离(米)
        private String origin;     // 起点地址
        private String destination; // 终点地址
        private boolean success;   // 是否成功
        private String message;    // 返回信息
        // getters and setters
        public int getDuration() {
            return duration;
        }
        public void setDuration(int duration) {
            this.duration = duration;
        }
        public int getDistance() {
            return distance;
        }
        public void setDistance(int distance) {
            this.distance = distance;
        }
        public String getOrigin() {
            return origin;
        }
        public void setOrigin(String origin) {
            this.origin = origin;
        }
        public String getDestination() {
            return destination;
        }
        public void setDestination(String destination) {
            this.destination = destination;
        }
        public boolean isSuccess() {
            return success;
        }
        public void setSuccess(boolean success) {
            this.success = success;
        }
        public String getMessage() {
            return message;
        }
        public void setMessage(String message) {
            this.message = message;
            this.apiKey = apiKey;
            this.httpClient = new OkHttpClient.Builder()
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .writeTimeout(10, TimeUnit.SECONDS)
                    .build();
            this.objectMapper = new ObjectMapper();
        }
        /**
         * 获取格式化的步行时间
         * @return 格式化的时间字符串(如:15分钟30秒)
         * 位置坐标类
         */
        public String getFormattedDuration() {
        public static class Location {
            private final double longitude; // 经度
            private final double latitude;  // 纬度
            int seconds = duration;
            int minutes = seconds / 60;
            seconds = seconds % 60;
            return String.format("%d分%d秒", minutes, seconds);
            public Location(double longitude, double latitude) {
                this.longitude = longitude;
                this.latitude = latitude;
            }
            public double getLongitude() {
                return longitude;
            }
            public double getLatitude() {
                return latitude;
            }
            @Override
            public String toString() {
                return String.format("%.6f,%.6f", longitude, latitude);
            }
        }
        /**
         * 获取格式化的步行距离
         * @return 格式化的距离字符串(如:1.2公里)
         * 步行路线结果类
         */
        public String getFormattedDistance() {
            if (distance >= 1000) {
                double km = distance / 1000.0;
                return String.format("%.1f公里", km);
            } else {
                return String.format("%d米", distance);
            }
        }
    }
        public static class WalkingRouteResult {
            private int duration;      // 步行时间(秒)
            private int distance;      // 步行距离(米)
            private String origin;     // 起点地址
            private String destination; // 终点地址
            private boolean success;   // 是否成功
            private String message;    // 返回信息
    /**
     * 根据地址获取经纬度坐标
     * @param address 地址信息
     * @return 经纬度坐标
     */
    public Location getLocationByAddress(String address) throws IOException {
        Map<String, String> params = new HashMap<>();
        params.put("key", apiKey);
        params.put("address", address);
        String url = buildUrl(AMAP_GEOCODING_URL, params);
        Request request = new Request.Builder().url(url).build();
        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("请求失败: " + response);
            // getters and setters
            public int getDuration() {
                return duration;
            }
            String responseBody = response.body().string();
            JsonNode rootNode = objectMapper.readTree(responseBody);
            public void setDuration(int duration) {
                this.duration = duration;
            }
            if ("1".equals(rootNode.get("status").asText())) {
                JsonNode geocodes = rootNode.get("geocodes");
                if (geocodes != null && geocodes.size() > 0) {
                    String locationStr = geocodes.get(0).get("location").asText();
                    String[] locationArray = locationStr.split(",");
                    double longitude = Double.parseDouble(locationArray[0]);
                    double latitude = Double.parseDouble(locationArray[1]);
                    return new Location(longitude, latitude);
            public int getDistance() {
                return distance;
            }
            public void setDistance(int distance) {
                this.distance = distance;
            }
            public String getOrigin() {
                return origin;
            }
            public void setOrigin(String origin) {
                this.origin = origin;
            }
            public String getDestination() {
                return destination;
            }
            public void setDestination(String destination) {
                this.destination = destination;
            }
            public boolean isSuccess() {
                return success;
            }
            public void setSuccess(boolean success) {
                this.success = success;
            }
            public String getMessage() {
                return message;
            }
            public void setMessage(String message) {
                this.message = message;
            }
            /**
             * 获取格式化的步行时间
             * @return 格式化的时间字符串(如:15分钟30秒)
             */
            public String getFormattedDuration() {
                int seconds = duration;
                int minutes = seconds / 60;
                seconds = seconds % 60;
                return String.format("%d分%d秒", minutes, seconds);
            }
            /**
             * 获取格式化的步行距离
             * @return 格式化的距离字符串(如:1.2公里)
             */
            public String getFormattedDistance() {
                if (distance >= 1000) {
                    double km = distance / 1000.0;
                    return String.format("%.1f公里", km);
                } else {
                    return String.format("%d米", distance);
                }
            }
            throw new IOException("地址解析失败: " + rootNode.get("info").asText());
        }
    }
    /**
     * 获取步行路线和时间
     * @param origin 起点坐标
     * @param destination 终点坐标
     * @return 步行路线结果
     */
    public WalkingRouteResult getWalkingRoute(Location origin, Location destination) {
        WalkingRouteResult result = new WalkingRouteResult();
        try {
        /**
         * 根据地址获取经纬度坐标
         * @param address 地址信息
         * @return 经纬度坐标
         */
        public Location getLocationByAddress (String address) throws IOException {
            Map<String, String> params = new HashMap<>();
            params.put("key", apiKey);
            params.put("origin", origin.toString());
            params.put("destination", destination.toString());
            params.put("address", address);
            String url = buildUrl(AMAP_API_BASE_URL, params);
            String url = buildUrl(AMAP_GEOCODING_URL, params);
            Request request = new Request.Builder().url(url).build();
            try (Response response = httpClient.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    result.setSuccess(false);
                    result.setMessage("HTTP请求失败: " + response.code());
                    return result;
                    throw new IOException("请求失败: " + response);
                }
                String responseBody = response.body().string();
                JsonNode rootNode = objectMapper.readTree(responseBody);
                String status = rootNode.get("status").asText();
                String info = rootNode.get("info").asText();
                if ("1".equals(status)) {
                    JsonNode route = rootNode.get("route");
                    JsonNode paths = route.get("paths");
                    if (paths != null && paths.size() > 0) {
                        JsonNode firstPath = paths.get(0);
                        int duration = firstPath.get("duration").asInt();
                        int distance = firstPath.get("distance").asInt();
                        result.setDuration(duration);
                        result.setDistance(distance);
                        result.setSuccess(true);
                        result.setMessage("成功获取步行路线");
                        // 尝试获取地址信息
                        result.setOrigin(getAddressByLocation(origin));
                        result.setDestination(getAddressByLocation(destination));
                    } else {
                        result.setSuccess(false);
                        result.setMessage("未找到步行路线");
                        log.info("未找到步行路线");
                        throw new ServiceException("未找到步行路线", I18nKeyConstant.NO_WALKING_ROUTE_FOUND);
                if ("1".equals(rootNode.get("status").asText())) {
                    JsonNode geocodes = rootNode.get("geocodes");
                    if (geocodes != null && geocodes.size() > 0) {
                        String locationStr = geocodes.get(0).get("location").asText();
                        String[] locationArray = locationStr.split(",");
                        double longitude = Double.parseDouble(locationArray[0]);
                        double latitude = Double.parseDouble(locationArray[1]);
                        return new Location(longitude, latitude);
                    }
                } else {
                    result.setSuccess(false);
                    result.setMessage("API返回错误: " + info);
                    log.info("API返回错误" + info);
                    throw new ServiceException("未找到步行路线", I18nKeyConstant.NO_WALKING_ROUTE_FOUND);
                }
                throw new IOException("地址解析失败: " + rootNode.get("info").asText());
            }
        } catch (Exception e) {
            result.setSuccess(false);
            result.setMessage("获取步行路线失败: " + e.getMessage());
            log.info("获取步行路线失败" + e.getMessage());
            throw new ServiceException("未找到步行路线", I18nKeyConstant.NO_WALKING_ROUTE_FOUND);
        }
        return result;
    }
        /**
         * 获取步行路线和时间
         * @param origin 起点坐标
         * @param destination 终点坐标
         * @return 步行路线结果
         */
        public WalkingRouteResult getWalkingRoute (Location origin, Location destination){
            WalkingRouteResult result = new WalkingRouteResult();
    /**
     * 根据经纬度获取地址(逆地理编码)
     * @param location 经纬度坐标
     * @return 地址信息
     */
    private String getAddressByLocation(Location location) {
        try {
            Map<String, String> params = new HashMap<>();
            params.put("key", apiKey);
            params.put("location", location.toString());
            try {
                Map<String, String> params = new HashMap<>();
                params.put("key", apiKey);
                params.put("origin", origin.toString());
                params.put("destination", destination.toString());
            String url = buildUrl("https://restapi.amap.com/v3/geocode/regeo", params);
            Request request = new Request.Builder().url(url).build();
                String url = buildUrl(AMAP_API_BASE_URL, params);
                Request request = new Request.Builder().url(url).build();
            try (Response response = httpClient.newCall(request).execute()) {
                if (response.isSuccessful()) {
                try (Response response = httpClient.newCall(request).execute()) {
                    if (!response.isSuccessful()) {
                        result.setSuccess(false);
                        result.setMessage("HTTP请求失败: " + response.code());
                        return result;
                    }
                    String responseBody = response.body().string();
                    JsonNode rootNode = objectMapper.readTree(responseBody);
                    if ("1".equals(rootNode.get("status").asText())) {
                        JsonNode regeocode = rootNode.get("regeocode");
                        if (regeocode != null) {
                            return regeocode.get("formatted_address").asText();
                    String status = rootNode.get("status").asText();
                    String info = rootNode.get("info").asText();
                    if ("1".equals(status)) {
                        JsonNode route = rootNode.get("route");
                        JsonNode paths = route.get("paths");
                        if (paths != null && paths.size() > 0) {
                            JsonNode firstPath = paths.get(0);
                            int duration = firstPath.get("duration").asInt();
                            int distance = firstPath.get("distance").asInt();
                            result.setDuration(duration);
                            result.setDistance(distance);
                            result.setSuccess(true);
                            result.setMessage("成功获取步行路线");
                            // 尝试获取地址信息
                            result.setOrigin(getAddressByLocation(origin));
                            result.setDestination(getAddressByLocation(destination));
                        } else {
                            result.setSuccess(false);
                            result.setMessage("未找到步行路线");
                            log.info("未找到步行路线");
                            throw new ServiceException("未找到步行路线", I18nKeyConstant.NO_WALKING_ROUTE_FOUND);
                        }
                    } else {
                        result.setSuccess(false);
                        result.setMessage("API返回错误: " + info);
                        log.info("API返回错误" + info);
                        throw new ServiceException("未找到步行路线", I18nKeyConstant.NO_WALKING_ROUTE_FOUND);
                    }
                }
            } catch (Exception e) {
                result.setSuccess(false);
                result.setMessage("获取步行路线失败: " + e.getMessage());
                log.info("获取步行路线失败" + e.getMessage());
                throw new ServiceException("未找到步行路线", I18nKeyConstant.NO_WALKING_ROUTE_FOUND);
            }
            return result;
        }
        /**
         * 根据经纬度获取地址(逆地理编码)
         * @param location 经纬度坐标
         * @return 地址信息
         */
        private String getAddressByLocation (Location location){
            try {
                Map<String, String> params = new HashMap<>();
                params.put("key", apiKey);
                params.put("location", location.toString());
                String url = buildUrl("https://restapi.amap.com/v3/geocode/regeo", params);
                Request request = new Request.Builder().url(url).build();
                try (Response response = httpClient.newCall(request).execute()) {
                    if (response.isSuccessful()) {
                        String responseBody = response.body().string();
                        JsonNode rootNode = objectMapper.readTree(responseBody);
                        if ("1".equals(rootNode.get("status").asText())) {
                            JsonNode regeocode = rootNode.get("regeocode");
                            if (regeocode != null) {
                                return regeocode.get("formatted_address").asText();
                            }
                        }
                    }
                }
            } catch (Exception e) {
                // 地址解析失败时返回坐标
            }
        } catch (Exception e) {
            // 地址解析失败时返回坐标
            return location.toString();
        }
        return location.toString();
    }
    /**
     * 构建带参数的URL
     * @param baseUrl 基础URL
     * @param params 参数Map
     * @return 完整的URL
     */
    private String buildUrl(String baseUrl, Map<String, String> params) {
        StringBuilder urlBuilder = new StringBuilder(baseUrl).append("?");
        params.forEach((key, value) -> {
            urlBuilder.append(key).append("=").append(value).append("&");
        });
        // 删除最后一个&
        urlBuilder.deleteCharAt(urlBuilder.length() - 1);
        return urlBuilder.toString();
    }
        /**
         * 构建带参数的URL
         * @param baseUrl 基础URL
         * @param params 参数Map
         * @return 完整的URL
         */
        private String buildUrl (String baseUrl, Map < String, String > params){
            StringBuilder urlBuilder = new StringBuilder(baseUrl).append("?");
            params.forEach((key, value) -> {
                urlBuilder.append(key).append("=").append(value).append("&");
            });
            // 删除最后一个&
            urlBuilder.deleteCharAt(urlBuilder.length() - 1);
            return urlBuilder.toString();
        }
    /**
     * 计算两点间的直线距离(仅供参考,不是实际步行距离)
     * @param loc1 坐标1
     * @param loc2 坐标2
     * @return 直线距离(米)
     */
    public static double calculateStraightDistance(Location loc1, Location loc2) {
        double earthRadius = 6371000; // 地球半径(米)
        double lat1 = Math.toRadians(loc1.getLatitude());
        double lat2 = Math.toRadians(loc2.getLatitude());
        double deltaLat = Math.toRadians(loc2.getLatitude() - loc1.getLatitude());
        double deltaLon = Math.toRadians(loc2.getLongitude() - loc1.getLongitude());
        /**
         * 计算两点间的直线距离(仅供参考,不是实际步行距离)
         * @param loc1 坐标1
         * @param loc2 坐标2
         * @return 直线距离(米)
         */
        public static double calculateStraightDistance (Location loc1, Location loc2){
            double earthRadius = 6371000; // 地球半径(米)
            double lat1 = Math.toRadians(loc1.getLatitude());
            double lat2 = Math.toRadians(loc2.getLatitude());
            double deltaLat = Math.toRadians(loc2.getLatitude() - loc1.getLatitude());
            double deltaLon = Math.toRadians(loc2.getLongitude() - loc1.getLongitude());
        double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
                Math.cos(lat1) * Math.cos(lat2) *
                        Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
            double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
                    Math.cos(lat1) * Math.cos(lat2) *
                            Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
            double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return earthRadius * c;
    }
            return earthRadius * c;
        }
}
    }
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/GaodeMapService.java
@@ -8,6 +8,7 @@
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@@ -18,12 +19,10 @@
    private static final String WALKING_API_URL = "https://restapi.amap.com/v3/direction/walking";
    
    // 你的高德地图API Key
    private String apiKey;
//    @Value("${map.apikey}")
    private String apiKey="66ae577f63898dae3016d599fda57221";
    
    public GaodeMapService(String apiKey) {
        this.apiKey = apiKey;
    }
    /**
     * 获取步行路径规划
     * @param origin 起点坐标,格式:经度,纬度
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java
@@ -3,10 +3,12 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.api.dto.operation.PointMapQuery;
import com.xiaopeng.api.dto.order.HistoryEndPointsDto;
import com.xiaopeng.api.dto.order.HistoryStartPointsDto;
import com.xiaopeng.api.model.operation.XpPoint;
import com.xiaopeng.api.model.operation.XpSystemSetting;
import com.xiaopeng.api.query.operation.PointPageListQuery;
import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo;
import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo;
import com.xiaopeng.api.vo.order.XpPointsListVo;
@@ -17,17 +19,17 @@
import com.xiaopeng.operation.mapper.XpPointMapper;
import com.xiaopeng.operation.mapper.XpSystemSettingMapper;
import com.xiaopeng.operation.query.PointByNameQuery;
import com.xiaopeng.api.dto.operation.PointMapQuery;
import com.xiaopeng.api.query.operation.PointPageListQuery;
import com.xiaopeng.operation.service.XpPointService;
import com.xiaopeng.operation.utils.TimeRangeChecker;
import com.xiaopeng.operation.utils.holiday.HolidayUtil;
import com.xiaopeng.operation.utils.map.FastDistanceCalculator;
import com.xiaopeng.operation.vo.NearestNextVo;
import com.xiaopeng.operation.vo.NearestVo;
import com.xiaopeng.operation.vo.OrderDistanceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -51,14 +53,17 @@
    @Resource
    private RedisService redisService;
    @Resource
    private HolidayUtil holidayUtil;
    @Override
    public NearestVo nearest(NearestDto dto) {
        // 获取所有的站点信息
        List<XpPoint> list = list(new LambdaQueryWrapper<XpPoint>().eq(XpPoint::getOperationStatus, 2).isNotNull(XpPoint::getElectronicAreaId));
        List<XpPoint> list = list(new LambdaQueryWrapper<XpPoint>().eq(XpPoint::getOperationStatus, 2).eq(XpPoint::getPointType,1).isNotNull(XpPoint::getElectronicAreaId));
        NearestVo nearestVo = new NearestVo();
        List<NearestNextVo> nearestNextVos = new ArrayList<>();
        LocalTime now = LocalTime.now();
        // 走缓存
        Object orderDistanceObj = redisService.getCacheObject(CacheConstants.NEAR_POINT_DISTANCE);
        Integer orderDistance;
@@ -70,6 +75,40 @@
        }
        for (XpPoint xpPoint : list) {
            //  2非工作日  0工作日  1节假日 3调休日
            Integer holidayToday = holidayUtil.isHolidayToday();
            Integer operationType = xpPoint.getEffectivePeriod();
            if(operationType==1){
                boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now, xpPoint.getEffectiveTimePeriod());
                if (!inTime) {
                    continue;
                }
            }else if(operationType==2){
                if(holidayToday!=0){
                    continue;
                }
                boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now, xpPoint.getEffectiveTimePeriod());
                if (!inTime) {
                    continue;
                }
            }else if(operationType==3){
                if(holidayToday!=2){
                    continue;
                }
                boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now, xpPoint.getEffectiveTimePeriod());
                if (!inTime) {
                    continue;
                }
            }else if(operationType==4){
                if(holidayToday!=1){
                    continue;
                }
                boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now, xpPoint.getEffectiveTimePeriod());
                if (!inTime) {
                    continue;
                }
            }
            // 计算距离 小于的站点
            double v = FastDistanceCalculator.distanceFast(dto.getLatitude(), dto.getLongitude(), xpPoint.getPointLat(), xpPoint.getPointLon());
            if (v < orderDistance) {
@@ -82,6 +121,8 @@
                nearestNextVo.setAddress(xpPoint.getPointAddress());
                nearestNextVo.setTime(xpPoint.getParkingTimeLimit());
                nearestNextVo.setElectronicAreaId(xpPoint.getElectronicAreaId());
                nearestNextVos.add(nearestNextVo);
            }
        }
@@ -94,6 +135,7 @@
    }
    @Override
    public List<XpPoint> pointMap(PointMapQuery query) {
        List<XpPoint> list = this.baseMapper.pointMap(query);
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TimeRangeChecker.java
New file
@@ -0,0 +1,84 @@
package com.xiaopeng.operation.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class TimeRangeChecker {
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
    /**
     * 判断当前时间是否在时间段内
     * @param jsonArrayStr JSON数组字符串,格式如 ["08:00-12:00", "13:30-17:30", "18:00-21:00"]
     * @return true 如果在时间段内,false 如果不在
     */
    public static boolean isCurrentTimeInRanges(LocalTime now,String jsonArrayStr) {
        return isTimeInRanges(jsonArrayStr, now);
    }
    /**
     * 判断指定时间是否在时间段内
     * @param jsonArrayStr JSON数组字符串
     * @param time 要判断的时间
     * @return true 如果在时间段内,false 如果不在
     */
    public static boolean isTimeInRanges(String jsonArrayStr, LocalTime time) {
        if (jsonArrayStr == null || jsonArrayStr.isEmpty()) {
            return false;
        }
        try {
            // 直接解析为JSONArray
            JSONArray timeArray = JSON.parseArray(jsonArrayStr);
            if (timeArray == null || timeArray.isEmpty()) {
                return false;
            }
            // 遍历所有时间段
            for (int i = 0; i < timeArray.size(); i++) {
                String timeRange = timeArray.getString(i);
                if (isTimeInRange(time, timeRange)) {
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 判断时间是否在单个时间段内
     */
    private static boolean isTimeInRange(LocalTime time, String timeRange) {
        if (timeRange == null || !timeRange.contains("-")) {
            return false;
        }
        String[] parts = timeRange.split("-");
        if (parts.length != 2) {
            return false;
        }
        try {
            LocalTime start = LocalTime.parse(parts[0].trim(), TIME_FORMATTER);
            LocalTime end = LocalTime.parse(parts[1].trim(), TIME_FORMATTER);
            // 处理跨天的情况(如 22:00-02:00)
            if (end.isBefore(start)) {
                // 跨天时间段
                return !time.isBefore(start) || !time.isAfter(end);
            } else {
                // 正常时间段
                return !time.isBefore(start) && !time.isAfter(end);
            }
        } catch (Exception e) {
            return false;
        }
    }
}