From 0dd8ec867eb1ed398bc1b1e93538f55809df3679 Mon Sep 17 00:00:00 2001
From: “mitao” <“2763622819@qq.com”>
Date: 星期五, 13 二月 2026 22:24:27 +0800
Subject: [PATCH] feat:增加省市区级联接口

---
 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpRegionServiceImpl.java |  125 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 121 insertions(+), 4 deletions(-)

diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpRegionServiceImpl.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpRegionServiceImpl.java
index 1e849ff..b75f141 100644
--- a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpRegionServiceImpl.java
+++ b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpRegionServiceImpl.java
@@ -3,19 +3,27 @@
 
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.xiaopeng.api.model.operation.XpOpenCity;
+import com.xiaopeng.api.model.operation.XpRegion;
 import com.xiaopeng.common.core.constant.CacheConstants;
 import com.xiaopeng.common.redis.service.RedisService;
 import com.xiaopeng.operation.mapper.XpRegionMapper;
-import com.xiaopeng.api.model.operation.XpRegion;
+import com.xiaopeng.operation.service.XpOpenCityService;
 import com.xiaopeng.operation.service.XpRegionService;
+import com.xiaopeng.operation.vo.RegionCascaderVO;
 import com.xiaopeng.operation.vo.RegionDistrictSyncResultVO;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
-import java.util.Objects;
+import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -31,6 +39,8 @@
 
     @Resource
     private RedisService redisService;
+    @Resource
+    private XpOpenCityService openCityService;
 
     @Override
     public List<List<XpRegion>> getXpRegion() {
@@ -69,10 +79,116 @@
     }
 
     @Override
+    public List<RegionCascaderVO> getRegionCascader() {
+        List<Object> cacheList = redisService.getCacheList(CacheConstants.XP_REGION_CASCADER);
+        if (cacheList != null && !cacheList.isEmpty()) {
+            try {
+                return cacheList.stream()
+                        .filter(item -> item instanceof RegionCascaderVO)
+                        .map(item -> (RegionCascaderVO) item)
+                        .collect(Collectors.toList());
+            } catch (ClassCastException e) {
+                redisService.deleteObject(CacheConstants.XP_REGION_CASCADER);
+            }
+        }
+
+        List<XpRegion> regionList = this.baseMapper.selectList(Wrappers.lambdaQuery(XpRegion.class));
+        if (regionList == null || regionList.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<XpOpenCity> openCityList = openCityService.list(Wrappers.lambdaQuery(XpOpenCity.class)
+                .eq(XpOpenCity::getStatus, 1));
+        Set<String> openCityCodeSet = openCityList.stream()
+                .map(XpOpenCity::getCityCode)
+                .filter(StringUtils::isNotBlank)
+                .collect(Collectors.toCollection(HashSet::new));
+        Set<String> openDistrictCodeSet = openCityList.stream()
+                .map(XpOpenCity::getDistrictCode)
+                .filter(StringUtils::isNotBlank)
+                .collect(Collectors.toCollection(HashSet::new));
+
+        Map<Long, List<XpRegion>> childrenMap = regionList.stream()
+                .collect(Collectors.groupingBy(region -> region.getParentId() == null ? 0L : region.getParentId()));
+        List<XpRegion> provinceList = childrenMap.getOrDefault(0L, Collections.emptyList()).stream()
+                .sorted(REGION_COMPARATOR)
+                .collect(Collectors.toList());
+        List<RegionCascaderVO> result = provinceList.stream()
+                .map(region -> buildRegionNode(region, childrenMap, openCityCodeSet, openDistrictCodeSet))
+                .collect(Collectors.toList());
+
+        redisService.setCacheList(CacheConstants.XP_REGION_CASCADER, result);
+        return result;
+    }
+
+    private RegionCascaderVO buildRegionNode(XpRegion current,
+                                             Map<Long, List<XpRegion>> childrenMap,
+                                             Set<String> openCityCodeSet,
+                                             Set<String> openDistrictCodeSet) {
+        List<XpRegion> children = childrenMap.getOrDefault(current.getId(), Collections.emptyList()).stream()
+                .sorted(REGION_COMPARATOR)
+                .collect(Collectors.toList());
+        List<RegionCascaderVO> childNodes = children.stream()
+                .map(child -> buildRegionNode(child, childrenMap, openCityCodeSet, openDistrictCodeSet))
+                .collect(Collectors.toList());
+
+        Integer level = resolveRegionLevel(current.getCode());
+        Integer selfOpen = resolveSelfOpen(level, current.getCode(), openCityCodeSet, openDistrictCodeSet);
+        boolean hasOpenChild = childNodes.stream().anyMatch(node -> Integer.valueOf(1).equals(node.getIsOpen()));
+
+        RegionCascaderVO node = new RegionCascaderVO();
+        node.setCode(current.getCode());
+        node.setName(current.getName());
+        node.setLeaf(Integer.valueOf(3).equals(level));
+        node.setChildren(childNodes);
+        node.setIsOpen(selfOpen == 1 || hasOpenChild ? 1 : 0);
+        return node;
+    }
+
+    private Integer resolveRegionLevel(String code) {
+        if (StringUtils.isBlank(code) || code.length() < 4) {
+            return 3;
+        }
+        if (code.endsWith("0000")) {
+            return 1;
+        }
+        if (code.endsWith("00")) {
+            return 2;
+        }
+        return 3;
+    }
+
+    private Integer resolveSelfOpen(Integer level,
+                                    String code,
+                                    Set<String> openCityCodeSet,
+                                    Set<String> openDistrictCodeSet) {
+        if (StringUtils.isBlank(code)) {
+            return 0;
+        }
+        if (Integer.valueOf(2).equals(level)) {
+            return openCityCodeSet.contains(code) ? 1 : 0;
+        }
+        if (Integer.valueOf(3).equals(level)) {
+            return openDistrictCodeSet.contains(code) ? 1 : 0;
+        }
+        return 0;
+    }
+
+    private static final Comparator<XpRegion> REGION_COMPARATOR = Comparator
+            .comparing((XpRegion region) -> StringUtils.defaultString(region.getInitial()))
+            .thenComparing((XpRegion region) -> StringUtils.defaultString(region.getCode()));
+
+    @Override
     @Transactional(rollbackFor = Exception.class)
     public RegionDistrictSyncResultVO syncDistrictFromRegionAll() {
-        Long cityCount = Objects.requireNonNullElse(this.baseMapper.countCityForDistrictSync(), 0L);
-        Long candidateDistrictCount = Objects.requireNonNullElse(this.baseMapper.countCandidateDistrictForSync(), 0L);
+        Long cityCount = this.baseMapper.countCityForDistrictSync();
+        if (cityCount == null) {
+            cityCount = 0L;
+        }
+        Long candidateDistrictCount = this.baseMapper.countCandidateDistrictForSync();
+        if (candidateDistrictCount == null) {
+            candidateDistrictCount = 0L;
+        }
 
         List<XpRegion> missingDistrictList = this.baseMapper.selectMissingDistrictFromRegionAll();
         long insertedCount = 0L;
@@ -83,6 +199,7 @@
 
         redisService.deleteObject(CacheConstants.XP_REGION);
         redisService.deleteObject(CacheConstants.XP_REGION_CITY);
+        redisService.deleteObject(CacheConstants.XP_REGION_CASCADER);
 
         RegionDistrictSyncResultVO result = new RegionDistrictSyncResultVO();
         result.setCityCount(cityCount);

--
Gitblit v1.7.1