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().isBefore(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;
}
}