package com.xiaopeng.operation.service.impl; import cn.hutool.core.collection.CollUtil; 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.*; import com.xiaopeng.api.query.operation.PointListQuery; import com.xiaopeng.api.query.operation.PointPageListListQuery; import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo; import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo; import com.xiaopeng.api.vo.order.XpPointsListVo; import com.xiaopeng.api.vo.order.XpPointsSearchVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.operation.dto.NearestDto; import com.xiaopeng.operation.mapper.XpPointMapper; import com.xiaopeng.operation.mapper.XpSystemSettingMapper; import com.xiaopeng.operation.query.PointByNameQuery; import com.xiaopeng.operation.service.IXpElectronicFenceAreaService; import com.xiaopeng.operation.service.IXpElectronicFenceService; 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.stereotype.Service; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; /** *

* 点位管理 服务实现类 *

* * @author liu * @author WuGuanFengYue * @since 2026-02-03 */ @Service public class XpPointServiceImpl extends ServiceImpl implements XpPointService { @Resource private XpSystemSettingMapper xpSystemSettingMapper; @Resource private RedisService redisService; @Resource private HolidayUtil holidayUtil; @Resource private IXpElectronicFenceAreaService xpElectronicFenceAreaService; @Resource private IXpElectronicFenceService xpElectronicFenceService; @Override public NearestVo nearest(NearestDto dto) { // 走缓存 Object orderDistanceObj = redisService.getCacheObject(CacheConstants.NEAR_POINT_DISTANCE); Integer orderDistance; if (orderDistanceObj != null) { orderDistance = Integer.valueOf(orderDistanceObj.toString()); } else { XpSystemSetting xpSystemSetting = xpSystemSettingMapper.selectOne(null); orderDistance = xpSystemSetting.getNearPointDistance(); } // 获取所有的站点信息 List list = list(new LambdaQueryWrapper().eq(XpPoint::getOperationStatus, 2).eq(XpPoint::getPointType,1).isNotNull(XpPoint::getElectronicAreaId) // 添加距离计算字段 .apply("ST_Distance_Sphere(point({0}, {1}), point(point_lon, point_lat)) <= {2}", dto.getLongitude(), dto.getLatitude(), orderDistance)); NearestVo nearestVo = new NearestVo(); if(list.isEmpty()){ nearestVo.setPoints(new ArrayList<>()); nearestVo.setTotal(0); return nearestVo; } List nearestNextVos = new ArrayList<>(); LocalTime now = LocalTime.now(); List areaIds = list.stream().map(XpPoint::getElectronicAreaId).collect(Collectors.toList()); List xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds); List fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList()); List xpElectronicFences = new ArrayList<>(); if (CollUtil.isNotEmpty(fenceIds)) { xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds); } //判断当前点位是否在运营时间范围内 for (XpPoint xpPoint : list) { Integer operationType = xpPoint.getOperationType(); if(1 == operationType){ //与运营区同步 XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreas.stream().filter(s -> s.getId().equals(xpPoint.getElectronicAreaId())).findFirst().orElse(null); if(null == xpElectronicFenceArea){ continue; } XpElectronicFence xpElectronicFence = xpElectronicFences.stream().filter(s -> s.getId().equals(xpElectronicFenceArea.getElectronicId())).findFirst().orElse(null); if(null == xpElectronicFence){ continue; } //失效类型 1=永不失效 2=定时失效 Integer failureType = xpElectronicFence.getFailureType(); //永不失效,但是还未到开始时间 if(1 == failureType && LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime())){ continue; }else if(2 == failureType && (LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime()) || LocalDateTime.now().isAfter(xpElectronicFence.getFailureTime()))){ //定时失效,但是当前时间不在时间范围内 continue; } }else{ //自定义时间段 // 判断是否在时间段内 boolean intime = getInTime(now, xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod()); if (!intime) { continue; } } // 计算距离 小于的站点 double v = FastDistanceCalculator.distanceFast(dto.getLatitude(), dto.getLongitude(), xpPoint.getPointLat(), xpPoint.getPointLon()); if (v < orderDistance) { NearestNextVo nearestNextVo = new NearestNextVo(); nearestNextVo.setId(xpPoint.getId()); nearestNextVo.setName(xpPoint.getPointName()); nearestNextVo.setLatitude(xpPoint.getPointLat()); nearestNextVo.setLongitude(xpPoint.getPointLon()); nearestNextVo.setDistance(v); nearestNextVo.setAddress(xpPoint.getPointAddress()); nearestNextVo.setTime(xpPoint.getParkingTimeLimit()); nearestNextVo.setElectronicAreaId(xpPoint.getElectronicAreaId()); nearestNextVos.add(nearestNextVo); } } if (!nearestNextVos.isEmpty()) { nearestNextVos = nearestNextVos.stream().sorted(Comparator.comparing(NearestNextVo::getDistance)).collect(Collectors.toList()); } nearestVo.setPoints(nearestNextVos); nearestVo.setTotal(nearestNextVos.size()); return nearestVo; } public boolean getInTime(LocalTime now, Integer effectivePeriod, String effectiveTimePeriod){ // 2非工作日 0工作日 1节假日 3调休日 Integer holidayToday = holidayUtil.isHolidayToday(); if(effectivePeriod==1){ boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod); if (!inTime) { return false; } }else if(effectivePeriod==2){ if(holidayToday!=0){ return false; } boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod); if (!inTime) { return false; } }else if(effectivePeriod==3){ if(holidayToday!=2){ return false; } boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod); if (!inTime) { return false; } }else if(effectivePeriod==4){ if(holidayToday!=1){ return false; } boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod); if (!inTime) { return false; } } return true; } @Override public List pointMap(PointMapQuery query) { List list = this.baseMapper.pointMap(query); return list; } @Override public List listAll(PointListQuery query) { if(StringUtils.hasLength(query.getOperationStatus())){ String[] split = query.getOperationStatus().split(","); List statusIds = new ArrayList<>(); for (String s : split) { statusIds.add(Integer.valueOf(s)); } query.setOperationStatusIds(statusIds); } List list = this.baseMapper.listAll(query); return list; } @Override public List getHistoryStartPoints(HistoryStartPointsDto historyStartPointsDto) { List xpPoints = this.baseMapper.selectBatchIds(historyStartPointsDto.getPointIds()); ArrayList resultList = new ArrayList<>(10); for (XpPoint xpPoint : xpPoints) { XpHistoryStartPointsVo xpHistoryStartPointsVo = new XpHistoryStartPointsVo(); xpHistoryStartPointsVo.setName(xpPoint.getPointName()); xpHistoryStartPointsVo.setAddress(xpPoint.getPointAddress()); xpHistoryStartPointsVo.setLatitude(xpPoint.getPointLat()); xpHistoryStartPointsVo.setLongitude(xpPoint.getPointLon()); xpHistoryStartPointsVo.setId(xpPoint.getId()); double distanced = FastDistanceCalculator.distanceFastKm(historyStartPointsDto.getLat(), historyStartPointsDto.getLon(), xpPoint.getPointLat(), xpPoint.getPointLon()); xpHistoryStartPointsVo.setDistance(distanced); xpHistoryStartPointsVo.setTime(xpPoint.getParkingTimeLimit()); xpHistoryStartPointsVo.setElectronicAreaId(xpPoint.getElectronicAreaId()); resultList.add(xpHistoryStartPointsVo); } return resultList; } @Override public List getHistoryEndPoints(HistoryEndPointsDto historyEndPointsDto) { List xpPoints = this.baseMapper.selectBatchIds(historyEndPointsDto.getPointIds()); ArrayList resultList = new ArrayList<>(10); for (XpPoint xpPoint : xpPoints) { XpHistoryEndPointsVo xpHistoryEndPointsVo = new XpHistoryEndPointsVo(); xpHistoryEndPointsVo.setName(xpPoint.getPointName()); xpHistoryEndPointsVo.setAddress(xpPoint.getPointAddress()); xpHistoryEndPointsVo.setLatitude(xpPoint.getPointLat()); xpHistoryEndPointsVo.setLongitude(xpPoint.getPointLon()); xpHistoryEndPointsVo.setId(xpPoint.getId()); double distanced = FastDistanceCalculator.distanceFastKm(historyEndPointsDto.getLat(), historyEndPointsDto.getLon(), xpPoint.getPointLat(), xpPoint.getPointLon()); xpHistoryEndPointsVo.setDistance(distanced); xpHistoryEndPointsVo.setTime(xpPoint.getParkingTimeLimit()); xpHistoryEndPointsVo.setElectronicAreaId(xpPoint.getElectronicAreaId()); resultList.add(xpHistoryEndPointsVo); } return resultList; } @Override public XpPointsSearchVo queryPointByName(PointByNameQuery query) { XpPointsSearchVo searchVo = new XpPointsSearchVo(); List list = this.baseMapper.queryPointByName(query); if (list.isEmpty()) { return searchVo; } LocalTime now = LocalTime.now(); List areaIds = list.stream().map(XpPointsListVo::getElectronicAreaId).collect(Collectors.toList()); List xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds); List fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList()); List xpElectronicFences = new ArrayList<>(); if (CollUtil.isNotEmpty(fenceIds)) { xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds); } for (XpPointsListVo xpPointsListVo : list) { Integer operationType = xpPointsListVo.getOperationType(); if(1 == operationType){ //与运营区同步 XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreas.stream().filter(s -> s.getId().equals(xpPointsListVo.getElectronicAreaId())).findFirst().orElse(null); if(null == xpElectronicFenceArea){ // 不在运营段 xpPointsListVo.setState(0); } XpElectronicFence xpElectronicFence = xpElectronicFences.stream().filter(s -> s.getId().equals(xpElectronicFenceArea.getElectronicId())).findFirst().orElse(null); if(null == xpElectronicFence){ // 不在运营段 xpPointsListVo.setState(0); } //失效类型 1=永不失效 2=定时失效 Integer failureType = xpElectronicFence.getFailureType(); //永不失效,但是还未到开始时间 if(1 == failureType && LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime())){ xpPointsListVo.setState(0); }else if(2 == failureType && (LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime()) || LocalDateTime.now().isAfter(xpElectronicFence.getFailureTime()))){ //定时失效,但是当前时间不在时间范围内 xpPointsListVo.setState(0); } }else{ //自定义时间段 // 判断是否在时间段内 boolean intime = getInTime(now, xpPointsListVo.getEffectivePeriod(), xpPointsListVo.getEffectiveTimePeriod()); if (!intime) { // 不在运营段 xpPointsListVo.setState(0); } } } // 组装数据 并排序 剔除不在运营段的 数据 List resultList = list.stream() .peek(vo -> vo.setDistance(BigDecimal.valueOf(FastDistanceCalculator.distanceFast(query.getLat(), query.getLon(), vo.getLatitude(), vo.getLongitude())).setScale(0, RoundingMode.HALF_UP).doubleValue())) .filter(vo -> vo.getState() == 1).collect(Collectors.toList()); // 可用点位 List availablePoints = resultList.stream().filter(e -> query.getElectronicAreaId() != null && e.getElectronicAreaId().equals(query.getElectronicAreaId())).sorted(Comparator.comparing(XpPointsListVo::getDistance)).collect(Collectors.toList());// // 不可用点位 List unavailablePoints = resultList.stream().filter(e -> query.getElectronicAreaId() == null || !e.getElectronicAreaId().equals(query.getElectronicAreaId())).sorted(Comparator.comparing(XpPointsListVo::getDistance)).collect(Collectors.toList()); searchVo.setAvailablePoints(availablePoints); searchVo.setUnavailablePoints(unavailablePoints); return searchVo; } @Override public OrderDistanceVo getOrderDistance() { OrderDistanceVo orderDistanceVo = new OrderDistanceVo(); XpSystemSetting xpSystemSetting = xpSystemSettingMapper.selectOne(null); if (xpSystemSetting != null) { orderDistanceVo.setMaxDistance(xpSystemSetting.getOrderDistance()); orderDistanceVo.setMinDistance(xpSystemSetting.getMinOrderDistance()); orderDistanceVo.setAdsorptionDistance(xpSystemSetting.getAdsorptionDistance()); orderDistanceVo.setNearPointDistance(xpSystemSetting.getNearPointDistance()); return orderDistanceVo; } return orderDistanceVo; } @Override public PageInfo pageList(PointPageListListQuery query) { PageInfo pageInfo = new PageInfo<>(query.getPageNum(),query.getPageSize()); List list = this.baseMapper.pageList(pageInfo,query); pageInfo.setRecords(list); return pageInfo; } }