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.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.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;
|
|
/**
|
* <p>
|
* 点位管理 服务实现类
|
* </p>
|
*
|
* @author liu
|
* @author WuGuanFengYue
|
* @since 2026-02-03
|
*/
|
@Service
|
public class XpPointServiceImpl extends ServiceImpl<XpPointMapper, XpPoint> 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;
|
|
|
@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<XpPoint> list1 = list(new LambdaQueryWrapper<XpPoint>().eq(XpPoint::getOperationStatus, 2).eq(XpPoint::getPointType,1).isNotNull(XpPoint::getElectronicAreaId));
|
if(list1.size()<2){
|
return new NearestVo();
|
}
|
// 获取所有的站点信息
|
List<XpPoint> list = list(new LambdaQueryWrapper<XpPoint>().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<NearestNextVo> nearestNextVos = new ArrayList<>();
|
LocalTime now = LocalTime.now();
|
List<Long> areaIds = list.stream().map(XpPoint::getElectronicAreaId).collect(Collectors.toList());
|
List<XpElectronicFenceArea> xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds);
|
List<Long> fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList());
|
List<XpElectronicFence> xpElectronicFences = new ArrayList<>();
|
if (CollUtil.isNotEmpty(fenceIds)) {
|
xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds);
|
}
|
R<List<Long>> 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());
|
|
// 判断是否收藏
|
if(pointIdsByUserId!=null && !pointIdsByUserId.getData().isEmpty()){
|
if(pointIdsByUserId.getData().contains(xpPoint.getId())){
|
nearestNextVo.setIsCollect(1);
|
}
|
}
|
|
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<XpPoint> pointMap(PointMapQuery query) {
|
List<XpPoint> 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<XpPoint> listAll(PointListQuery query) {
|
if(StringUtils.hasLength(query.getOperationStatus())){
|
String[] split = query.getOperationStatus().split(",");
|
List<Integer> statusIds = new ArrayList<>();
|
for (String s : split) {
|
statusIds.add(Integer.valueOf(s));
|
}
|
query.setOperationStatusIds(statusIds);
|
}
|
List<XpPoint> 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<String, Double> 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<XpHistoryStartPointsVo> getHistoryStartPoints(HistoryStartPointsDto historyStartPointsDto) {
|
List<XpPoint> xpPoints = this.baseMapper.selectBatchIds(historyStartPointsDto.getPointIds());
|
ArrayList<XpHistoryStartPointsVo> resultList = new ArrayList<>(10);
|
|
LocalTime now = LocalTime.now();
|
List<Long> areaIds = xpPoints.stream().map(XpPoint::getElectronicAreaId).collect(Collectors.toList());
|
List<XpElectronicFenceArea> xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds);
|
List<Long> fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList());
|
|
List<XpElectronicFence> xpElectronicFences = new ArrayList<>();
|
if (CollUtil.isNotEmpty(fenceIds)) {
|
xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds);
|
}
|
|
// 获取用户收藏的地址
|
R<List<Long>> 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<XpHistoryEndPointsVo> getHistoryEndPoints(HistoryEndPointsDto historyEndPointsDto) {
|
List<XpPoint> xpPoints = this.baseMapper.selectBatchIds(historyEndPointsDto.getPointIds());
|
ArrayList<XpHistoryEndPointsVo> resultList = new ArrayList<>(10);
|
|
LocalTime now = LocalTime.now();
|
List<Long> areaIds = xpPoints.stream().map(XpPoint::getElectronicAreaId).collect(Collectors.toList());
|
List<XpElectronicFenceArea> xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds);
|
List<Long> fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList());
|
|
List<XpElectronicFence> xpElectronicFences = new ArrayList<>();
|
if (CollUtil.isNotEmpty(fenceIds)) {
|
xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds);
|
}
|
|
|
|
// 获取用户收藏的地址
|
R<List<Long>> 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<XpPointsListVo> stationList = this.baseMapper.queryStationByName(query);
|
List<Long> stationIds = stationList.stream()
|
.map(this::getSearchResultStationId)
|
.filter(Objects::nonNull)
|
.distinct()
|
.collect(Collectors.toList());
|
// 先把命中的场站id传给点位查询,避免同一场站下的点位和场站父胶囊重复返回。
|
List<XpPointsListVo> pointList = this.baseMapper.queryPointByName(query, stationIds);
|
List<XpPointsListVo> stationChildren = CollUtil.isEmpty(stationIds) ? Collections.emptyList() : this.baseMapper.queryStationChildren(stationIds);
|
if (CollUtil.isEmpty(stationList) && CollUtil.isEmpty(pointList)) {
|
return searchVo;
|
}
|
|
// 搜索页需要拆分两套收藏态:
|
// 1. 站点胶囊按 pointId 判定。
|
// 2. 场站胶囊按 stationId 判定。
|
Set<Long> collectedPointIds = getCollectedPointIds(uid);
|
Set<Long> collectedStationIds = getCollectedStationIds(uid);
|
List<XpPointsListVo> allRows = new ArrayList<>(stationList.size() + pointList.size() + stationChildren.size());
|
allRows.addAll(stationList);
|
allRows.addAll(pointList);
|
allRows.addAll(stationChildren);
|
|
Map<Long, XpElectronicFenceArea> electronicFenceAreaMap = buildElectronicFenceAreaMap(allRows);
|
Map<Long, XpElectronicFence> electronicFenceMap = buildElectronicFenceMap(electronicFenceAreaMap);
|
markSearchRows(allRows, collectedPointIds, collectedStationIds, electronicFenceAreaMap, electronicFenceMap);
|
|
List<XpPointsListVo> resultList = new ArrayList<>();
|
List<XpPointsListVo> stationResults = buildStationSearchResults(stationList, stationChildren, query);
|
Set<Long> 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<XpPointsListVo> availablePoints = resultList.stream()
|
.filter(e -> query.getElectronicAreaId() != null && e.getElectronicAreaId().equals(query.getElectronicAreaId()))
|
.sorted(Comparator.comparing(this::distanceOrMax))
|
.collect(Collectors.toList());
|
List<XpPointsListVo> 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;
|
}
|
|
private List<XpPointsListVo> buildStationSearchResults(List<XpPointsListVo> stationList,
|
List<XpPointsListVo> stationChildren,
|
PointByNameQuery query) {
|
if (CollUtil.isEmpty(stationList)) {
|
return Collections.emptyList();
|
}
|
Map<Long, List<XpPointsListVo>> childrenMap = stationChildren.stream()
|
.filter(vo -> vo.getState() == 1)
|
.peek(vo -> fillDistance(vo, query))
|
.collect(Collectors.groupingBy(this::getSearchResultStationId, LinkedHashMap::new, Collectors.toList()));
|
List<XpPointsListVo> result = new ArrayList<>();
|
for (XpPointsListVo station : stationList) {
|
if (station.getState() != 1) {
|
continue;
|
}
|
Long stationId = getSearchResultStationId(station);
|
List<XpPointsListVo> 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<Long> getCollectedPointIds(String uid) {
|
if (uid == null) {
|
return Collections.emptySet();
|
}
|
R<List<Long>> 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<Long> getCollectedStationIds(String uid) {
|
if (uid == null) {
|
return Collections.emptySet();
|
}
|
R<List<Long>> stationIdsByUserId = xpAppUserCollectAddrClient.getStationIdsByUserId(Long.valueOf(uid));
|
if (stationIdsByUserId == null || CollUtil.isEmpty(stationIdsByUserId.getData())) {
|
return Collections.emptySet();
|
}
|
return new HashSet<>(stationIdsByUserId.getData());
|
}
|
|
private Map<Long, XpElectronicFenceArea> buildElectronicFenceAreaMap(List<XpPointsListVo> rows) {
|
List<Long> 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<Long, XpElectronicFence> buildElectronicFenceMap(Map<Long, XpElectronicFenceArea> electronicFenceAreaMap) {
|
if (electronicFenceAreaMap.isEmpty()) {
|
return Collections.emptyMap();
|
}
|
List<Long> 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<XpPointsListVo> rows,
|
Set<Long> collectedPointIds,
|
Set<Long> collectedStationIds,
|
Map<Long, XpElectronicFenceArea> electronicFenceAreaMap,
|
Map<Long, XpElectronicFence> 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<Long> collectedPointIds,
|
Set<Long> 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<Long, XpElectronicFenceArea> electronicFenceAreaMap,
|
Map<Long, XpElectronicFence> 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();
|
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<XpPoint> pageList(PointPageListListQuery query) {
|
PageInfo<XpPoint> pageInfo = new PageInfo<>(query.getPageNum(),query.getPageSize());
|
List<XpPoint> 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;
|
}
|
}
|