package com.xiaopeng.operation.service.impl;
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.XpBanner;
import com.xiaopeng.api.model.operation.XpPoint;
import com.xiaopeng.api.model.operation.XpSystemSetting;
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.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.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;
@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();
List nearestNextVos = new ArrayList<>();
LocalTime now = LocalTime.now();
for (XpPoint xpPoint : list) {
// 判断是否在时间段内
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();
for (XpPointsListVo xpPointsListVo : list) {
boolean inTime = getInTime(now, xpPointsListVo.getEffectivePeriod(), xpPointsListVo.getEffectiveTimePeriod());
if (!inTime) {
// 不在运营段
xpPointsListVo.setState(0);
}
}
// 组装数据 并排序 剔除不在运营段的 数据
List resultList = list.stream().peek(vo -> vo.setDistance(FastDistanceCalculator.distanceFast(query.getLat(), query.getLon(), vo.getLatitude(), vo.getLongitude()))).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;
}
}