liujie
2026-02-13 776a0f3bc4f2e4ddf74732b4d5a7cbc9438cb06e
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);