From fa8e441c82c9d336d1144dd1ec925551d07b2299 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期日, 12 四月 2026 17:37:06 +0800
Subject: [PATCH] 1.0小程序功能 个人中心
---
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java | 293 +++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 225 insertions(+), 68 deletions(-)
diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java
index a13992d..a9b70a7 100644
--- a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java
+++ b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java
@@ -470,85 +470,242 @@
@Override
public XpPointsSearchVo queryPointByName(PointByNameQuery query,String uid) {
XpPointsSearchVo searchVo = new XpPointsSearchVo();
- List<XpPointsListVo> list = this.baseMapper.queryPointByName(query);
- if (list.isEmpty()) {
+ 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;
}
- LocalTime now = LocalTime.now();
- List<Long> areaIds = list.stream().map(XpPointsListVo::getElectronicAreaId).collect(Collectors.toList());
- List<XpElectronicFenceArea> xpElectronicFenceAreas = xpElectronicFenceAreaService.listByIds(areaIds);
- List<Long> fenceIds = xpElectronicFenceAreas.stream().map(XpElectronicFenceArea::getElectronicId).collect(Collectors.toList());
+ // 搜索页需要拆分两套收藏态:
+ // 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);
- List<XpElectronicFence> xpElectronicFences = new ArrayList<>();
- if (CollUtil.isNotEmpty(fenceIds)) {
- xpElectronicFences = xpElectronicFenceService.listByIds(fenceIds);
- }
+ 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()));
- R<List<Long>> pointIdsByUserId =null;
- // 获取用户收藏的地址
- if(uid!=null){
- pointIdsByUserId = xpAppUserCollectAddrClient.getPointIdsByUserId(Long.valueOf(uid));
- }
-
- for (XpPointsListVo xpPointsListVo : list) {
-
- // 判断是否收藏
- if(pointIdsByUserId!=null && !pointIdsByUserId.getData().isEmpty()){
- if(pointIdsByUserId.getData().contains(xpPointsListVo.getId())){
- xpPointsListVo.setIsCollect(1);
- }
- }
-
-
- 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<XpPointsListVo> resultList = list.stream()
- .peek(vo -> vo.setDistance(BigDecimal.valueOf(FastDistanceCalculator.distanceFast(query.getLat(), query.getLon(), vo.getLatitude(), vo.getLongitude())).setScale(2, RoundingMode.HALF_UP).doubleValue()))
- .filter(vo -> vo.getState() == 1).collect(Collectors.toList());
-
- // 可用点位
- List<XpPointsListVo> availablePoints = resultList.stream().filter(e -> query.getElectronicAreaId() != null && e.getElectronicAreaId().equals(query.getElectronicAreaId())).sorted(Comparator.comparing(XpPointsListVo::getDistance)).collect(Collectors.toList());//
-
- // 不可用点位
- List<XpPointsListVo> unavailablePoints = resultList.stream().filter(e -> query.getElectronicAreaId() == null || !e.getElectronicAreaId().equals(query.getElectronicAreaId())).sorted(Comparator.comparing(XpPointsListVo::getDistance)).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();
--
Gitblit v1.7.1