package com.xiaopeng.operation.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.feignClient.account.XpAppUserCollectAddrClient;
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.utils.GeodesyUtil;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.evi.oss.service.AliOssService;
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.IXpTradingStrategyService;
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.api.vo.operation.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.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
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;
@Resource
private XpPointMapper baseMapper;
@Resource
private XpAppUserCollectAddrClient xpAppUserCollectAddrClient;
@Resource
private AliOssService aliOssService;
@Resource
private IXpTradingStrategyService xpTradingStrategyService;
/**
* 如果站点是挂在场站下的 需要返回一个场站id stationId
* @param dto
* @param uid
* @return
*/
@Override
public NearestVo nearest(NearestDto dto,String uid) {
// 走缓存
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 list1 = list(new LambdaQueryWrapper().eq(XpPoint::getOperationStatus, 2).eq(XpPoint::getPointType,1).isNotNull(XpPoint::getElectronicAreaId));
if(list1.size()<2){
return new NearestVo();
}
// 获取所有的站点信息
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));
list = list.stream().filter(e->e.getElectronicAreaId().equals(dto.getElectronicAreaId())).collect(Collectors.toList());
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);
}
R> pointIdsByUserId = null;
// 获取用户收藏的地址
if(uid!=null){
pointIdsByUserId = xpAppUserCollectAddrClient.getPointIdsByUserId(Long.valueOf(uid));
}
//判断当前点位是否在运营时间范围内
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());
// m做判断
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(new BigDecimal(v).setScale(2, RoundingMode.HALF_UP).doubleValue());
nearestNextVo.setAddress(xpPoint.getPointAddress());
nearestNextVo.setTime(xpPoint.getParkingTimeLimit());
nearestNextVo.setElectronicAreaId(xpPoint.getElectronicAreaId());
nearestNextVo.setStationId(xpPoint.getStationId()==null?null:xpPoint.getStationId().toString());
nearestNextVo.setIsCollect(2);
// 判断是否收藏
if(pointIdsByUserId.getData()!=null && !pointIdsByUserId.getData().isEmpty()){
if(pointIdsByUserId.getData().contains(xpPoint.getId())){
nearestNextVo.setIsCollect(1);
}
}
nearestNextVos.add(nearestNextVo);
}
}
List objects = new ArrayList();
if (!nearestNextVos.isEmpty()) {
//收藏的数据
List collect = nearestNextVos.stream().filter(s -> s.getIsCollect() == 1)
.sorted(Comparator.comparing(NearestNextVo::getDistance)).collect(Collectors.toList());
objects.addAll(collect);
//非收藏的数据
List collect1 = nearestNextVos.stream().filter(s -> s.getIsCollect() == 2)
.sorted(Comparator.comparing(NearestNextVo::getDistance)).collect(Collectors.toList());
objects.addAll(collect1);
}
nearestVo.setPoints(objects);
nearestVo.setTotal(objects.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);
for (XpPoint xpPoint : list) {
String pointPictures = xpPoint.getPointPictures();
if (org.apache.commons.lang3.StringUtils.isNotBlank(pointPictures)) {
JSONArray jsonArray = JSONArray.parseArray(pointPictures);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
if (Objects.isNull(jsonObject)) {
continue;
}
String downloadUrl = jsonObject.getString("url");;
try {
downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
} catch (UnsupportedEncodingException e) {
log.error("获取图片下载地址失败", e);
}
jsonObject.put("url", downloadUrl);
}
xpPoint.setPointPictures(JSONArray.toJSONString(jsonArray));
}
}
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);
for (XpPoint xpPoint : list) {
String pointPictures = xpPoint.getPointPictures();
if (org.apache.commons.lang3.StringUtils.isNotBlank(pointPictures)) {
JSONArray jsonArray = JSONArray.parseArray(pointPictures);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
if (Objects.isNull(jsonObject)) {
continue;
}
String downloadUrl = jsonObject.getString("url");;
// try {
// downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
// } catch (UnsupportedEncodingException e) {
// log.error("获取图片下载地址失败", e);
// }
jsonObject.put("url", downloadUrl);
}
xpPoint.setPointPictures(JSONArray.toJSONString(jsonArray));
}
if(null != query.getLongitude() && null != query.getLatitude()){
Map distance = GeodesyUtil.getDistance(query.getLongitude() + "," + query.getLatitude(), xpPoint.getPointLon() + "," + xpPoint.getPointLat());
xpPoint.setDistance(new BigDecimal(distance.get("WGS84")));
}
}
if(null != query.getLongitude() && null != query.getLatitude()){
//对距离进行排序
list.sort((o1, o2) -> o1.getDistance().compareTo(o2.getDistance()) * -1);
}
return list;
}
@Override
public List getHistoryStartPoints(HistoryStartPointsDto historyStartPointsDto) {
List xpPoints = this.baseMapper.selectBatchIds(historyStartPointsDto.getPointIds());
if(xpPoints.isEmpty()){
return new ArrayList<>();
}
ArrayList resultList = new ArrayList<>(10);
LocalTime now = LocalTime.now();
List areaIds = xpPoints.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);
}
// 获取用户收藏的地址
R> pointIdsByUserId = xpAppUserCollectAddrClient.getPointIdsByUserId(historyStartPointsDto.getUserId());
for (XpPoint xpPoint : xpPoints) {
if(xpPoint.getOperationStatus()!=2){
continue;
}
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;
}
}
XpHistoryStartPointsVo xpHistoryStartPointsVo = new XpHistoryStartPointsVo();
xpHistoryStartPointsVo.setOperationStatus(1);
xpHistoryStartPointsVo.setName(xpPoint.getPointName());
xpHistoryStartPointsVo.setAddress(xpPoint.getPointAddress());
xpHistoryStartPointsVo.setLatitude(xpPoint.getPointLat());
xpHistoryStartPointsVo.setLongitude(xpPoint.getPointLon());
xpHistoryStartPointsVo.setId(xpPoint.getId());
double distanced = FastDistanceCalculator.distanceFast(historyStartPointsDto.getLat(), historyStartPointsDto.getLon(), xpPoint.getPointLat(), xpPoint.getPointLon());
xpHistoryStartPointsVo.setDistance(distanced);
xpHistoryStartPointsVo.setTime(xpPoint.getParkingTimeLimit());
xpHistoryStartPointsVo.setElectronicAreaId(xpPoint.getElectronicAreaId());
// 判断是否收藏
if(pointIdsByUserId!=null && !pointIdsByUserId.getData().isEmpty()){
if(pointIdsByUserId.getData().contains(xpPoint.getId())){
xpHistoryStartPointsVo.setIsCollect(1);
}
}
resultList.add(xpHistoryStartPointsVo);
}
return resultList;
}
@Override
public List getHistoryEndPoints(HistoryEndPointsDto historyEndPointsDto) {
List xpPoints = this.baseMapper.selectBatchIds(historyEndPointsDto.getPointIds());
if(xpPoints.isEmpty()){
return new ArrayList();
}
ArrayList resultList = new ArrayList<>(10);
LocalTime now = LocalTime.now();
List areaIds = xpPoints.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);
}
// 获取用户收藏的地址
R> pointIdsByUserId = xpAppUserCollectAddrClient.getPointIdsByUserId(historyEndPointsDto.getUserId());
for (XpPoint xpPoint : xpPoints) {
if(xpPoint.getOperationStatus()!=2){
continue;
}
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;
}
}
XpHistoryEndPointsVo xpHistoryEndPointsVo = new XpHistoryEndPointsVo();
xpHistoryEndPointsVo.setOperationStatus(1);
xpHistoryEndPointsVo.setName(xpPoint.getPointName());
xpHistoryEndPointsVo.setAddress(xpPoint.getPointAddress());
xpHistoryEndPointsVo.setLatitude(xpPoint.getPointLat());
xpHistoryEndPointsVo.setLongitude(xpPoint.getPointLon());
xpHistoryEndPointsVo.setId(xpPoint.getId());
double distanced = FastDistanceCalculator.distanceFast(historyEndPointsDto.getLat(), historyEndPointsDto.getLon(), xpPoint.getPointLat(), xpPoint.getPointLon());
xpHistoryEndPointsVo.setDistance(distanced);
xpHistoryEndPointsVo.setTime(xpPoint.getParkingTimeLimit());
xpHistoryEndPointsVo.setElectronicAreaId(xpPoint.getElectronicAreaId());
// 判断是否收藏
if(pointIdsByUserId!=null && !pointIdsByUserId.getData().isEmpty()){
if(pointIdsByUserId.getData().contains(xpPoint.getId())){
xpHistoryEndPointsVo.setIsCollect(1);
}
}
resultList.add(xpHistoryEndPointsVo);
}
return resultList;
}
@Override
public XpPointsSearchVo queryPointByName(PointByNameQuery query,String uid) {
XpPointsSearchVo searchVo = new XpPointsSearchVo();
List stationList = this.baseMapper.queryStationByName(query);
List stationIds = stationList.stream()
.map(this::getSearchResultStationId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
// 先把命中的场站id传给点位查询,避免同一场站下的点位和场站父胶囊重复返回。
List pointList = this.baseMapper.queryPointByName(query, stationIds);
List stationChildren = CollUtil.isEmpty(stationIds) ? Collections.emptyList() : this.baseMapper.queryStationChildren(stationIds);
if (CollUtil.isEmpty(stationList) && CollUtil.isEmpty(pointList)) {
return searchVo;
}
// 搜索页需要拆分两套收藏态:
// 1. 站点胶囊按 pointId 判定。
// 2. 场站胶囊按 stationId 判定。
Set collectedPointIds = getCollectedPointIds(uid);
Set collectedStationIds = getCollectedStationIds(uid);
List allRows = new ArrayList<>(stationList.size() + pointList.size() + stationChildren.size());
allRows.addAll(stationList);
allRows.addAll(pointList);
allRows.addAll(stationChildren);
Map electronicFenceAreaMap = buildElectronicFenceAreaMap(allRows);
Map electronicFenceMap = buildElectronicFenceMap(electronicFenceAreaMap);
markSearchRows(allRows, collectedPointIds, collectedStationIds, electronicFenceAreaMap, electronicFenceMap);
List resultList = new ArrayList<>();
List stationResults = buildStationSearchResults(stationList, stationChildren, query);
Set displayedStationIds = stationResults.stream()
.map(this::getSearchResultStationId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
resultList.addAll(stationResults);
resultList.addAll(pointList.stream()
.filter(vo -> vo.getState() == 1)
.filter(vo -> vo.getStationId() == null || !displayedStationIds.contains(vo.getStationId()))
.peek(vo -> fillDistance(vo, query))
.collect(Collectors.toList()));
List availablePoints = resultList.stream()
.filter(e -> query.getElectronicAreaId() != null && e.getElectronicAreaId().equals(query.getElectronicAreaId()))
.sorted(Comparator.comparing(this::distanceOrMax))
.collect(Collectors.toList());
List unavailablePoints = resultList.stream()
.filter(e -> query.getElectronicAreaId() == null || !e.getElectronicAreaId().equals(query.getElectronicAreaId()))
.sorted(Comparator.comparing(this::distanceOrMax))
.collect(Collectors.toList());
searchVo.setAvailablePoints(availablePoints);
searchVo.setUnavailablePoints(unavailablePoints);
return searchVo;
}
@Override
public List getStationChildren(Long stationId) {
if (stationId == null) {
return Collections.emptyList();
}
return this.baseMapper.queryStationChildren(Arrays.asList(stationId));
}
private List buildStationSearchResults(List stationList,
List stationChildren,
PointByNameQuery query) {
if (CollUtil.isEmpty(stationList)) {
return Collections.emptyList();
}
Map> childrenMap = stationChildren.stream()
.filter(vo -> vo.getState() == 1)
.peek(vo -> fillDistance(vo, query))
.collect(Collectors.groupingBy(this::getSearchResultStationId, LinkedHashMap::new, Collectors.toList()));
List result = new ArrayList<>();
for (XpPointsListVo station : stationList) {
if (station.getState() != 1) {
continue;
}
Long stationId = getSearchResultStationId(station);
List children = childrenMap.getOrDefault(stationId, Collections.emptyList());
if (CollUtil.isEmpty(children)) {
continue;
}
XpPointsListVo firstChild = children.get(0);
if (station.getCollectPointId() == null) {
station.setCollectPointId(firstChild.getId());
}
if (station.getLongitude() == null || station.getLatitude() == null) {
station.setLongitude(firstChild.getLongitude());
station.setLatitude(firstChild.getLatitude());
}
if (!StringUtils.hasLength(station.getAddress())) {
station.setAddress(firstChild.getAddress());
}
fillDistance(station, query);
station.setChildren(children);
result.add(station);
}
return result;
}
/**
* 仅查询“站点收藏”。
* nearest / 历史上下车点等老接口仍然只对 pointId 打星,所以这里不能混入场站收藏。
*/
private Set getCollectedPointIds(String uid) {
if (uid == null) {
return Collections.emptySet();
}
R> pointIdsByUserId = xpAppUserCollectAddrClient.getPointIdsByUserId(Long.valueOf(uid));
if (pointIdsByUserId == null || CollUtil.isEmpty(pointIdsByUserId.getData())) {
return Collections.emptySet();
}
return new HashSet<>(pointIdsByUserId.getData());
}
/**
* 场站收藏需要单独查询。
* 搜索结果里的场站父级行应按 stationId 判断收藏态,不能继续复用 pointId 集合。
*/
private Set getCollectedStationIds(String uid) {
if (uid == null) {
return Collections.emptySet();
}
R> stationIdsByUserId = xpAppUserCollectAddrClient.getStationIdsByUserId(Long.valueOf(uid));
if (stationIdsByUserId == null || CollUtil.isEmpty(stationIdsByUserId.getData())) {
return Collections.emptySet();
}
return new HashSet<>(stationIdsByUserId.getData());
}
private Map buildElectronicFenceAreaMap(List rows) {
List areaIds = rows.stream()
.map(XpPointsListVo::getElectronicAreaId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (CollUtil.isEmpty(areaIds)) {
return Collections.emptyMap();
}
return xpElectronicFenceAreaService.listByIds(areaIds).stream()
.collect(Collectors.toMap(XpElectronicFenceArea::getId, area -> area, (left, right) -> left));
}
private Map buildElectronicFenceMap(Map electronicFenceAreaMap) {
if (electronicFenceAreaMap.isEmpty()) {
return Collections.emptyMap();
}
List fenceIds = electronicFenceAreaMap.values().stream()
.map(XpElectronicFenceArea::getElectronicId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (CollUtil.isEmpty(fenceIds)) {
return Collections.emptyMap();
}
return xpElectronicFenceService.listByIds(fenceIds).stream()
.collect(Collectors.toMap(XpElectronicFence::getId, fence -> fence, (left, right) -> left));
}
private void markSearchRows(List rows,
Set collectedPointIds,
Set collectedStationIds,
Map electronicFenceAreaMap,
Map electronicFenceMap) {
LocalTime now = LocalTime.now();
for (XpPointsListVo row : rows) {
if (isCollectedSearchRow(row, collectedPointIds, collectedStationIds)) {
row.setIsCollect(1);
}
if (!isSearchRowAvailable(row, electronicFenceAreaMap, electronicFenceMap, now)) {
row.setState(0);
}
}
}
/**
* 搜索结果收藏态判定规则:
* 1. 站点行按 pointId / collectPointId 判定。
* 2. 场站行按 stationId 判定。
*/
private boolean isCollectedSearchRow(XpPointsListVo row,
Set collectedPointIds,
Set collectedStationIds) {
if (row.getItemType() != null && row.getItemType() == 2) {
Long stationId = getSearchResultStationId(row);
return stationId != null && collectedStationIds.contains(stationId);
}
Long collectPointId = row.getCollectPointId() != null ? row.getCollectPointId() : row.getId();
return collectPointId != null && collectedPointIds.contains(collectPointId);
}
private boolean isSearchRowAvailable(XpPointsListVo row,
Map electronicFenceAreaMap,
Map electronicFenceMap,
LocalTime now) {
Integer operationType = row.getOperationType();
if (operationType == null) {
return false;
}
if (operationType == 1) {
Long electronicAreaId = row.getElectronicAreaId();
if (electronicAreaId == null) {
return false;
}
XpElectronicFenceArea electronicFenceArea = electronicFenceAreaMap.get(electronicAreaId);
if (electronicFenceArea == null || electronicFenceArea.getElectronicId() == null) {
return false;
}
XpElectronicFence electronicFence = electronicFenceMap.get(electronicFenceArea.getElectronicId());
if (electronicFence == null) {
return false;
}
Integer failureType = electronicFence.getFailureType();
if (failureType == null) {
return true;
}
if (failureType == 1 && LocalDateTime.now().isBefore(electronicFence.getEffectTime())) {
return false;
}
return failureType != 2 || (!LocalDateTime.now().isBefore(electronicFence.getEffectTime())
&& !LocalDateTime.now().isAfter(electronicFence.getFailureTime()));
}
if (row.getEffectivePeriod() == null || !StringUtils.hasLength(row.getEffectiveTimePeriod())) {
return true;
}
return getInTime(now, row.getEffectivePeriod(), row.getEffectiveTimePeriod());
}
private void fillDistance(XpPointsListVo row, PointByNameQuery query) {
if (row.getLatitude() == null || row.getLongitude() == null) {
return;
}
row.setDistance(BigDecimal.valueOf(FastDistanceCalculator.distanceFast(query.getLat(), query.getLon(), row.getLatitude(), row.getLongitude()))
.setScale(2, RoundingMode.HALF_UP)
.doubleValue());
}
private Long getSearchResultStationId(XpPointsListVo row) {
return row.getStationId() != null ? row.getStationId() : row.getId();
}
private Double distanceOrMax(XpPointsListVo row) {
return row.getDistance() == null ? Double.MAX_VALUE : row.getDistance();
}
@Override
public OrderDistanceVo getOrderDistance() {
OrderDistanceVo orderDistanceVo = new OrderDistanceVo();
XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null);
if(null != xpTradingStrategy){
orderDistanceVo.setQueuePollingTime(xpTradingStrategy.getQueuePollingTime());
orderDistanceVo.setWalkingNavigationDistance(xpTradingStrategy.getWalkingNavigationDistance());
orderDistanceVo.setMaxStandingTiming(xpTradingStrategy.getMaxStandingTiming());
}
XpSystemSetting xpSystemSetting = xpSystemSettingMapper.selectOne(null);
if (xpSystemSetting != null) {
orderDistanceVo.setMaxDistance(xpSystemSetting.getOrderDistance());
orderDistanceVo.setMinDistance(xpSystemSetting.getMinOrderDistance());
orderDistanceVo.setAdsorptionDistance(xpSystemSetting.getAdsorptionDistance());
orderDistanceVo.setNearPointDistance(xpSystemSetting.getNearPointDistance());
orderDistanceVo.setTemperatureUnit(xpSystemSetting.getTemperatureUnit());
orderDistanceVo.setXczSyDistance(xpSystemSetting.getXczSyDistance());
orderDistanceVo.setXczSyTime(xpSystemSetting.getXczSyTime());
orderDistanceVo.setXczCaCount(xpSystemSetting.getXczCaCount());
orderDistanceVo.setXczHmSpeedPerHour(xpSystemSetting.getXczHmSpeedPerHour());
orderDistanceVo.setXczHmDuration(xpSystemSetting.getXczHmDuration());
orderDistanceVo.setOperateFree(xpSystemSetting.getOperateFree());
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;
}
@Override
public Boolean nowInTimePoint(Long pointId) {
XpPoint xpPoint = this.getById(pointId);
if(null == xpPoint){
return false;
}
Integer operationType = xpPoint.getOperationType();
if(1 == operationType){
//与运营区同步
XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreaService.getById(xpPoint.getElectronicAreaId());
if(null == xpElectronicFenceArea){
return false;
}
XpElectronicFence xpElectronicFence = xpElectronicFenceService.getById(xpElectronicFenceArea.getElectronicId());
if(null == xpElectronicFence){
return false;
}
//失效类型 1=永不失效 2=定时失效
Integer failureType = xpElectronicFence.getFailureType();
//永不失效,但是还未到开始时间
if(1 == failureType && LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime())){
return false;
}else if(2 == failureType && (LocalDateTime.now().isBefore(xpElectronicFence.getEffectTime()) || LocalDateTime.now().isAfter(xpElectronicFence.getFailureTime()))){
//定时失效,但是当前时间不在时间范围内
return false;
}
}else{
//自定义时间段
// 判断是否在时间段内
boolean intime = getInTime(LocalTime.now(), xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod());
if (!intime) {
return false;
}
}
return true;
}
}