package com.xiaopeng.operation.service.impl;
|
|
|
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.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.Map;
|
import java.util.Set;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 省市区三级联动 服务实现类
|
* </p>
|
*
|
* @author liu
|
* @since 2026-02-03
|
*/
|
@Service
|
public class XpRegionServiceImpl extends ServiceImpl<XpRegionMapper, XpRegion> implements XpRegionService {
|
|
@Resource
|
private RedisService redisService;
|
@Resource
|
private XpOpenCityService openCityService;
|
|
@Override
|
public List<List<XpRegion>> getXpRegion() {
|
|
// 缓存数据
|
List<Object> cacheList = redisService.getCacheList(CacheConstants.XP_REGION);
|
if (cacheList != null && !cacheList.isEmpty()) {
|
try {
|
return cacheList.stream()
|
.filter(obj -> obj instanceof List)
|
.map(obj -> {
|
List<?> list = (List<?>) obj;
|
return list.stream()
|
.filter(item -> item instanceof XpRegion)
|
.map(item -> (XpRegion) item)
|
.collect(Collectors.toList());
|
})
|
.collect(Collectors.toList());
|
} catch (ClassCastException e) {
|
// 缓存数据结构异常,重新加载
|
redisService.deleteObject(CacheConstants.XP_REGION);
|
}
|
}
|
String[] initials = {"A", "B", "C", "D", "E", "F",
|
"G", "H", "I", "J", "K", "L",
|
"M", "N", "O", "P", "Q", "R",
|
"S", "T", "U", "V", "W", "X", "Y", "Z"};
|
List<XpRegion> tRegions = this.baseMapper.selectList(Wrappers.lambdaQuery(XpRegion.class));
|
List<List<XpRegion>> result = new ArrayList<>();
|
for (String initial : initials) {
|
List<XpRegion> init = tRegions.stream().filter(e -> e.getInitial().equals(initial) && !e.getCode().contains("0000")).collect(Collectors.toList());
|
result.add(init);
|
}
|
redisService.setCacheList(CacheConstants.XP_REGION, result);
|
return result;
|
}
|
|
@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()));
|
|
}
|