package com.xiaopeng.map.service.serviceimpl; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.api.dto.map.RouteAndFareDto; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.feignClient.operation.XpElectronicFenceClient; import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient; import com.xiaopeng.api.model.map.XpGeoFencingPolygon; import com.xiaopeng.api.model.operation.XpElectronicFence; import com.xiaopeng.api.model.operation.XpElectronicFenceArea; import com.xiaopeng.api.vo.operation.XpElectronicFenceVo; import com.xiaopeng.api.vo.operation.XpPointsVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.utils.DateUtils; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.map.dto.WalkTimeDto; import com.xiaopeng.map.mangodb.model.GeoPoint; import com.xiaopeng.map.mangodb.service.XpGeoFencingPolygonService; import com.xiaopeng.map.mapper.XpElectronicFenceAreaMapper; import com.xiaopeng.map.mapper.XpElectronicFenceMapper; import com.xiaopeng.map.service.XpElectronicFenceAreaService; import com.xiaopeng.map.utils.AmapWalkingRouteUtil; import com.xiaopeng.map.utils.ElectricFenceUtil; import com.xiaopeng.map.utils.GDMapGeocodingUtil; import com.xiaopeng.map.utils.GaodeMapService; import com.xiaopeng.map.utils.holiday.HolidayUtil; import com.xiaopeng.map.vo.IsInOperationAreaVo; import com.xiaopeng.map.vo.WalkTimeVo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** *

* 电子围栏区域构成 服务实现类 *

* * @author liu * @since 2026-02-03 */ @Service public class XpElectronicFenceAreaServiceImpl extends ServiceImpl implements XpElectronicFenceAreaService { @Resource private XpElectronicFenceClient xpElectronicFenceClient; @Resource private XpSystemSettingClient xpSystemSettingClient; @Resource private XpGeoFencingPolygonService xpGeoFencingPolygonService; @Resource private RedisService redisService; @Resource private HolidayUtil holidayUtil; @Autowired private MongoTemplate mongoTemplate; @Resource private GDMapGeocodingUtil gdMapGeocodingUtil; @Override public List citiesList(String cityCode) { List xpGeoFencingPolygons = mongoTemplate.find(new Query(Criteria.where("cityCode").is(cityCode)), XpGeoFencingPolygon.class); if(xpGeoFencingPolygons.isEmpty()){ return new ArrayList<>(); } List result = new ArrayList<>(); List fenceIds = xpGeoFencingPolygons.stream().map(XpGeoFencingPolygon::getFenceId).collect(Collectors.toList()); if(fenceIds.isEmpty()){ return new ArrayList<>(); } R> xpElectronicFences = xpElectronicFenceClient.selectBatchIds(fenceIds); if(xpElectronicFences==null){ return new ArrayList<>(); } for (XpGeoFencingPolygon polygon : xpGeoFencingPolygons) { XpElectronicFence xpElectronicFence = xpElectronicFences.getData().stream().filter(e -> e.getId().toString().equals(polygon.getFenceId())).findFirst().orElse(null); if(xpElectronicFence==null){ continue; } String operationStrategy = xpElectronicFence.getOperationStrategy(); if(operationStrategy==null){ continue; } // 是否运营时间内 if(xpElectronicFence.getFailureType() == 2){ Boolean inOperationTime = isInOperationTime(operationStrategy); if(!inOperationTime){ continue; } }else{ //永不失效,需要判断开始时间是否到达 if(LocalDateTime.now().isAfter(xpElectronicFence.getEffectTime())){ continue; } } XpElectronicFenceVo vo = new XpElectronicFenceVo(); // 设置id(使用siteId作为id) vo.setFenceId(polygon.getFenceId()); vo.setAreaId(polygon.getAreaId()); // 设置围栏名称 vo.setName(polygon.getName()); // 转换GeoJsonPolygon为List List pointsVoList = new ArrayList<>(); if (polygon.getPoints() != null && polygon.getPoints().getCoordinates() != null) { // GeoJsonPolygon的coordinates是一个二维数组,第一个元素是外部环 List points = polygon.getPoints().getPoints(); for (Point coord : points) { XpPointsVo pointsVo = new XpPointsVo(); // GeoJson的坐标顺序是[经度, 纬度] // x经度 y维度 pointsVo.setLng(coord.getX()); pointsVo.setLat(coord.getY()); pointsVoList.add(pointsVo); } } vo.setPoints(pointsVoList); result.add(vo); } return result; } /** * 是否在运营内 * @param operationStrategy 规则json字符串 * @return */ private Boolean isInOperationTime(String operationStrategy) { JSONArray jsonArray = JSONArray.parseArray(operationStrategy); Integer holidayToday = holidayUtil.isHolidayToday(); for (Object o : jsonArray) { JSONObject jsonObject =JSONObject.parseObject(o.toString()); String type = jsonObject.getString("type"); if(type.equals(holidayToday.toString())){ JSONArray time = jsonObject.getJSONArray("time"); // 判断当前时间 是否在time时间段中 for (Object object : time) { String[] timeArray = object.toString().split("-"); String startTime = timeArray[0]; String endTime = timeArray[1]; boolean currentTimeInRange = DateUtils.isCurrentTimeInRange(startTime, endTime); if(currentTimeInRange){ return true; } } }else if(type.equals("3")){ // 判断是什么类型 0每天 1-7 想起 String typeStr = jsonObject.getString("typeStr"); // 查看今天周几 Integer week = DateUtils.getWeek(); // 包含每天 或者 包含当天 if(typeStr.contains("0") || typeStr.contains(week.toString())){ JSONArray time = jsonObject.getJSONArray("time"); // 判断当前时间 是否在time时间段中 for (Object object : time) { String[] timeArray = object.toString().split("-"); String startTime = timeArray[0]; String endTime = timeArray[1]; boolean currentTimeInRange = DateUtils.isCurrentTimeInRange(startTime, endTime); if(currentTimeInRange){ return true; } } } } } return false; } /** * 判断经纬度是否在开放区域中 * @param dto * @return */ @Override public IsInOperationAreaVo isInOperationArea(LonLatDto dto) { IsInOperationAreaVo vo = new IsInOperationAreaVo(); Map geocode = gdMapGeocodingUtil.geocode(dto.getLongitude().toString(), dto.getLatitude().toString()); if(null == geocode){ throw new RuntimeException("经纬度转换城市code失败"); } String cityCode = geocode.get("cityCode"); List xpGeoFencingPolygons = mongoTemplate.find(new Query(Criteria.where("cityCode").is(cityCode)), XpGeoFencingPolygon.class); for (XpGeoFencingPolygon polygon : xpGeoFencingPolygons) { if (polygon.getPoints() != null && polygon.getPoints().getCoordinates() != null) { // GeoJsonPolygon的coordinates是一个二维数组,第一个元素是外部环 ArrayList coordinates = new ArrayList<>(); List points = polygon.getPoints().getPoints(); for (Point point : points) { coordinates.add( point.getX()+","+point.getY() ); } String collect = coordinates.stream().collect(Collectors.joining(";")); if (ElectricFenceUtil.areaMonitoring(collect, dto.getLongitude()+","+dto.getLatitude())) { String fenceId = polygon.getFenceId(); R xpElectronicFence = xpElectronicFenceClient.selectById(fenceId); if(xpElectronicFence!=null && null != xpElectronicFence.getData()){ XpElectronicFence electronicFence = xpElectronicFence.getData(); String operationStrategy = electronicFence.getOperationStrategy(); Boolean inOperationTime = true; if(electronicFence.getFailureType() == 2){ inOperationTime = isInOperationTime(operationStrategy); } if(inOperationTime){ vo.setStatus("inside"); vo.setElectronicAreaId(Long.valueOf(polygon.getAreaId())); return vo; } } } } } return vo; // try { // executor.execute(() -> { // for (XpElectronicFenceVo xpElectronicFenceVo : xpElectronicFenceVos) { // ArrayList geoPoints = new ArrayList<>(); // // 获取多边形顶点坐标 // List points = xpElectronicFenceVo.getPoints(); // for (XpPointsVo point : points) { // geoPoints.add(new AmapGeoFenceUtil.GeoPoint(point.getLng(), point.getLat())); // } // AmapGeoFenceUtil.GeoFence geoFence = new AmapGeoFenceUtil.GeoFence(); // geoFence.setPoints(geoPoints); // // AmapGeoFenceUtil.GeoFenceResult geoFenceResult = null; // try { // // // ElectricFenceUtil.areaMonitoring() // geoFenceResult = amapGeoFenceUtil.checkInPolygonFence(geoPoint, geoFence); // if (geoFenceResult.isInFence()) { // vo.setStatus("inside"); // } // } catch (IOException e) { // throw new RuntimeException(e); // } // } // }); // return vo; // }catch (Exception e){ // e.printStackTrace(); // vo.setStatus("outside"); // }finally { // gracefulShutdown(executor); // } // // return vo; } /** * 优雅关闭线程池通用方法 * * @param pool 需要关闭的线程池 */ private static void gracefulShutdown(ExecutorService pool) { pool.shutdown(); // 拒绝新任务提交 try { // 等待现有任务完成 if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); // 取消等待中的任务 只等待运行中的任务 // 再次等待任务响应中断 if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { } } } catch (InterruptedException e) { // 重新尝试关闭 pool.shutdownNow(); Thread.currentThread().interrupt(); } finally { } } @Override public WalkTimeVo getWalkTime(WalkTimeDto dto) { WalkTimeVo walkTimeVo = new WalkTimeVo(); // 创建服务实例 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()); System.out.println("步行距离: " + result.getFormattedDistance()); walkTimeVo.setWalkTime(result.getFormattedDuration()); walkTimeVo.setWalkDistance(result.getFormattedDistance()); Double orderDistanceDouble = 0.0; // 走缓存 Object orderDistance = redisService.getCacheObject(CacheConstants.ORDER_DISTANCE); if (orderDistance != null) { orderDistanceDouble = Double.parseDouble(orderDistance.toString()); }else { R r = xpSystemSettingClient.getOrderDistance(); if (r.getCode()==200) { Object orderDistanceObj = r.getData(); if (orderDistanceObj != null) { orderDistanceDouble = Double.parseDouble(orderDistanceObj.toString()); } } } if(orderDistanceDouble>result.getDistance()){ walkTimeVo.setStatus(1); } return walkTimeVo; }else { System.out.println("错误信息: " + result.getMessage()); // 抛出异常 throw new RuntimeException(result.getMessage()); } } @Override public Boolean diagnosisArea(RouteAndFareDto dto) { // 起点数据 GeoPoint startPoint = new GeoPoint(dto.getOrigin().getLongitude(),dto.getOrigin().getLatitude()); // 终点数据 GeoPoint endPoint = new GeoPoint(dto.getDestination().getLongitude(),dto.getDestination().getLatitude()); List operatingArea = xpGeoFencingPolygonService.findFencesContainingPoint(startPoint, "operating_area", "points"); if (!operatingArea.isEmpty()) { List operatingArea2 = xpGeoFencingPolygonService.findFencesContainingPoint(endPoint, "operating_area", "points"); if (!operatingArea2.isEmpty()) { // "开始判断是否在相同区域"; if(operatingArea.get(0).equals(operatingArea2.get(0))){ return true; } } } return null; } }