puzhibing
2026-04-28 19787c0b4f5f29026c1790bbb043b9186cdd0e11
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpPointServiceImpl.java
@@ -12,15 +12,12 @@
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.XpElectronicFenceArea;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpPoint;
import com.xiaopeng.api.model.operation.XpRegion;
import com.xiaopeng.api.model.operation.XpStation;
import com.xiaopeng.api.model.operation.XpSystemSetting;
import com.xiaopeng.api.model.operation.*;
import com.xiaopeng.api.query.operation.FenceAndStationVo;
import com.xiaopeng.api.query.operation.PointListQuery;
import com.xiaopeng.api.query.operation.PointPageListListQuery;
import com.xiaopeng.api.query.operation.XpStationQuery;
import com.xiaopeng.api.vo.account.LoginUser;
import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo;
import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo;
import com.xiaopeng.api.vo.order.XpPointsListVo;
@@ -31,19 +28,19 @@
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.common.security.service.TokenService;
import com.xiaopeng.evi.oss.service.AliOssService;
import com.xiaopeng.map.constant.I18nKeyConstant;
import com.xiaopeng.map.dto.NearestDto;
import com.xiaopeng.map.dto.StationDetailQueryDto;
import com.xiaopeng.map.mapper.XpPointMapper;
import com.xiaopeng.map.mapper.XpElectronicFenceMapper;
import com.xiaopeng.map.mapper.XpPointMapper;
import com.xiaopeng.map.mapper.XpRegionMapper;
import com.xiaopeng.map.mapper.XpSystemSettingMapper;
import com.xiaopeng.map.query.PointByNameQuery;
import com.xiaopeng.map.service.XpElectronicFenceAreaService;
import com.xiaopeng.map.service.XpPointService;
import com.xiaopeng.map.service.XpStationService;
import com.xiaopeng.map.utils.TimeRangeChecker;
import com.xiaopeng.map.utils.holiday.HolidayUtil;
import com.xiaopeng.map.utils.map.map.FastDistanceCalculator;
import com.xiaopeng.map.vo.*;
@@ -116,6 +113,9 @@
    @Autowired
    private AliOssService aliOssService;
    @Lazy
    @Autowired
    private BootCommonService bootCommonService;
    @Override
    @Transactional
@@ -228,10 +228,18 @@
            orderDistance = xpSystemSetting.getNearPointDistance();
        }
        // 获取所有的站点信息
        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));
        PointPageListListQuery query =  new PointPageListListQuery();
        query.setOperationStatus(2);
        query.setPointType(1);
        query.setElectronicAreaIdNotNull(true);
        query.setLongitude(dto.getLongitude());
        query.setLatitude(dto.getLatitude());
        query.setOrderDistance(orderDistance);
        List<XpPoint> list = baseMapper.pageList(query);
        // 添加距离计算字段
//        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));
        NearestVo nearestVo = new NearestVo();
        List<NearestNextVo> nearestNextVos = new ArrayList<>();
        LocalTime now = LocalTime.now();
@@ -239,7 +247,7 @@
        for (XpPoint xpPoint : list) {
            // 判断是否在时间段内
            boolean intime = getInTime(now, xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod());
            boolean intime = bootCommonService.getPointOperation(now, xpPoint);
            if (!intime) {
                continue;
            }
@@ -325,42 +333,6 @@
    }
    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) {
@@ -462,37 +434,47 @@
            return stationDetailVo;
        }
        XpStation station = xpStationService.getById(dto.getStationId());
        if (station == null || !isStationAvailable(station)) {
        XpStationQuery query = new XpStationQuery();
        query.setId(dto.getStationId());
        query.setStatus(2);
        List<XpStation> list = xpStationService.findList(query);
        if(CollUtil.isEmpty(list)){
            return stationDetailVo;
        }
        XpStation station = list.get(0);
        LocalTime localTime = LocalTime.now();
        boolean stationOperation = bootCommonService.getStationOperation(localTime, station.getOperationType(), station.getEffectivePeriod(), station.getEffectiveTimePeriod(), station.getFenceOperationStrategy());
        if(!stationOperation){
            return stationDetailVo;
        }
        // 仅查询场站下运营点位,最终结果还会叠加时段/围栏有效性过滤。
        List<XpPoint> stationPoints = this.lambdaQuery()
                .eq(XpPoint::getStationId, station.getId())
                .eq(XpPoint::getPointType, 1)
                .eq(XpPoint::getOperationStatus, 2)
                .list();
        PointPageListListQuery queryPoint = new PointPageListListQuery();
        queryPoint.setStationId( station.getId());
        queryPoint.setPointType(1);
        queryPoint.setOperationStatus(2);
        List<XpPoint> stationPoints = this.baseMapper.pageList(queryPoint);
        if (CollUtil.isEmpty(stationPoints)) {
            return stationDetailVo;
        }
        Map<Long, XpElectronicFenceArea> areaMap = buildAreaMap(stationPoints.stream()
                .map(XpPoint::getElectronicAreaId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList()));
        Map<Long, XpElectronicFence> fenceMap = buildFenceMap(areaMap.values().stream()
                .map(XpElectronicFenceArea::getElectronicId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList()));
//        Map<Long, XpElectronicFenceArea> areaMap = buildAreaMap(stationPoints.stream()
//                .map(XpPoint::getElectronicAreaId)
//                .filter(Objects::nonNull)
//                .distinct()
//                .collect(Collectors.toList()));
//        Map<Long, XpElectronicFence> fenceMap = buildFenceMap(areaMap.values().stream()
//                .map(XpElectronicFenceArea::getElectronicId)
//                .filter(Objects::nonNull)
//                .distinct()
//                .collect(Collectors.toList()));
        Set<Long> collectStationIds = getCollectStationIds(uid);
        Set<Long> collectPointIds = getCollectPointIds(uid);
        // 默认点位优先置顶,其余点位再按场站内排序和距离排序。
        List<StationPointItemVo> points = stationPoints.stream()
                .filter(point -> isPointAvailable(point, areaMap, fenceMap))
                .filter(point -> isPointAvailable(localTime, point))
                .map(point -> toStationPointItem(point, station.getDefaultPointId(), dto.getLatitude(), dto.getLongitude(), collectPointIds))
                .sorted(buildStationPointComparator())
                .collect(Collectors.toList());
@@ -519,10 +501,10 @@
        if (list.isEmpty()) {
            return searchVo;
        }
        LocalTime now = LocalTime.now();
        for (XpPointsListVo xpPointsListVo : list) {
            boolean inTime = getInTime(now, xpPointsListVo.getEffectivePeriod(), xpPointsListVo.getEffectiveTimePeriod());
            boolean inTime = bootCommonService.getPointOperation_vo(now, xpPointsListVo);
            if (!inTime) {
                // 不在运营段
                xpPointsListVo.setState(0);
@@ -557,35 +539,16 @@
        return orderDistanceVo;
    }
    @Override
    public PageInfo<XpPoint> pageList(PointPageListListQuery query) {
        if(CollUtil.isNotEmpty(query.getFenceAndStationList())){
            List<String> fenceAreaIds = new ArrayList<>();
            List<String> stationIds = new ArrayList<>();
            for (FenceAndStationVo bean : query.getFenceAndStationList()) {
                if(bean.getType()==1){
                    fenceAreaIds.addAll(StrUtil.split(bean.getIds(),",") );
                }else{
                    stationIds.addAll(StrUtil.split(bean.getIds(),",") );
                }
            }
            query.setFenceAreaIds(fenceAreaIds);
            query.setStationIds(stationIds);
    public List<XpPoint> pageList(PageInfo<XpPoint> pageInfo, PointPageListListQuery query) {
        List<XpPoint> list = null;
        if (pageInfo == null) {
            list = this.baseMapper.pageList(query);
        }else{
            list = this.baseMapper.pageList(pageInfo,query);
        }
        PageInfo<XpPoint> pageInfo = new PageInfo<>(query.getPageNum(),query.getPageSize());
        if (StringUtils.isNotBlank(query.getPointLonAndLat())) {
            List<String> lonAndLat = query.getPointLonAndLat().trim().contains(",") ? Arrays.asList(query.getPointLonAndLat().split(",")) :
                    query.getPointLonAndLat().trim().contains(" ") ? Arrays.asList(query.getPointLonAndLat().split(" ")) :
                            Collections.emptyList();
            if (CollUtil.isNotEmpty(lonAndLat)) {
                query.setPointLon(lonAndLat.get(0));
                query.setPointLat(lonAndLat.get(1));
                query.setPointLonAndLat(null);
            }
        }
        List<XpPoint> list = this.baseMapper.pageList(pageInfo,query);
        if(CollUtil.isNotEmpty(list)){
            /**
             * hover在状态标签时,展示信息
@@ -603,11 +566,11 @@
                }
                if(point.getVerificationStatus()==5 && point.getOperationStatus() == 1){
                    if(point.getOperationType() ==  1){//运营类型 1=与运营区同步 2=自定义时间段
                         ;
                        ;
                        //[{"name": "策略组1", "time": ["06:00-12:00", "13:00-22:59"], "type": 0, "typeStr": []},
                        // {"name": "策略组2", "time": ["05:00-12:00", "12:00-16:00"], "type": 2, "typeStr": ""},
                        // {"name": "策略组3", "time": ["09:00-21:59"], "type": 1, "typeStr": ""}]
                        JSONArray electronicOperationStrategys = JSONArray.parseArray(point.getElectronicOperationStrategy());
                        JSONArray electronicOperationStrategys = JSONArray.parseArray(point.getFenceOperationStrategy());
                        if(!electronicOperationStrategys.isEmpty()){
                            StringJoiner joiner = new StringJoiner(";");
                            for (Object electronicOperationStrategy : electronicOperationStrategys) {
@@ -622,13 +585,43 @@
                        if(StrUtil.isNotBlank(point.getEffectiveTimePeriod()) ){
                            List<String> effectiveTimePeriods = JSONArray.parseArray(point.getEffectiveTimePeriod(), String.class);
                            hoverStatusDes = String.join(";", effectiveTimePeriods);
//                        hoverStatusDes = "待生效:"+point.getElectronicEffectTime().toString()  ;
                        }
                    }
                }
                point.setHoverStatusDes(hoverStatusDes);
            }
        }
        return list;
    }
    @Override
    public PageInfo<XpPoint> pageList(PointPageListListQuery query) {
        if(CollUtil.isNotEmpty(query.getFenceAndStationList())){
            List<String> fenceAreaIds = new ArrayList<>();
            List<String> stationIds = new ArrayList<>();
            for (FenceAndStationVo bean : query.getFenceAndStationList()) {
                if(bean.getType()==1){
                    fenceAreaIds.addAll(StrUtil.split(bean.getIds(),",") );
                }else{
                    stationIds.addAll(StrUtil.split(bean.getIds(),",") );
                }
            }
            query.setFenceAreaIds(fenceAreaIds);
            query.setStationIds(stationIds);
        }
        PageInfo<XpPoint> pageInfo = new PageInfo<>(query.getPageNum(),query.getPageSize());
        if (StringUtils.isNotBlank(query.getPointLonAndLat())) {
            List<String> lonAndLat = query.getPointLonAndLat().trim().contains(",") ? Arrays.asList(query.getPointLonAndLat().split(",")) :
                    query.getPointLonAndLat().trim().contains(" ") ? Arrays.asList(query.getPointLonAndLat().split(" ")) :
                            Collections.emptyList();
            if (CollUtil.isNotEmpty(lonAndLat)) {
                query.setPointLon(lonAndLat.get(0));
                query.setPointLat(lonAndLat.get(1));
                query.setPointLonAndLat(null);
            }
        }
        List<XpPoint> list = this.pageList(pageInfo,query);
        pageInfo.setRecords(list);
        return pageInfo;
    }
@@ -652,75 +645,19 @@
                .collect(Collectors.toMap(XpElectronicFence::getId, fence -> fence, (a, b) -> a));
    }
    /**
     * 场站可展示判断:
     * 1. 状态必须为启用中;
     * 2. 与运营区同步时,依赖运营区和围栏的当前有效性;
     * 3. 自定义时段时,依赖场站自身时段配置。
     */
    private boolean isStationAvailable(XpStation station) {
        if (station == null || !Integer.valueOf(6).equals(station.getStatus())) {
            return false;
        }
        if (Integer.valueOf(1).equals(station.getOperationType())) {
            if (station.getElectronicAreaId() == null) {
                return false;
            }
            XpElectronicFenceArea area = xpElectronicFenceAreaService.getById(station.getElectronicAreaId());
            if (area == null || !Integer.valueOf(1).equals(area.getAreaStatus()) || area.getElectronicId() == null) {
                return false;
            }
            XpElectronicFence fence = xpElectronicFenceMapper.selectById(area.getElectronicId());
            return isFenceAvailable(fence);
        }
        if (Integer.valueOf(2).equals(station.getOperationType())
                && station.getEffectivePeriod() != null
                && StringUtils.isNotBlank(station.getEffectiveTimePeriod())) {
            return getInTime(LocalTime.now(), station.getEffectivePeriod(), station.getEffectiveTimePeriod());
        }
        return false;
    }
    /**
     * 子点位是否可展示与场站卡片中。
     * 规则与现有点位有效性保持一致,避免地图页和其他点位查询出现口径偏差。
     */
    private boolean isPointAvailable(XpPoint point, Map<Long, XpElectronicFenceArea> areaMap, Map<Long, XpElectronicFence> fenceMap) {
        if (point == null || !Integer.valueOf(2).equals(point.getOperationStatus())) {
            return false;
        }
        if (Integer.valueOf(1).equals(point.getOperationType())) {
            if (point.getElectronicAreaId() == null) {
                return false;
            }
            XpElectronicFenceArea area = areaMap.get(point.getElectronicAreaId());
            if (area == null || !Integer.valueOf(1).equals(area.getAreaStatus()) || area.getElectronicId() == null) {
                return false;
            }
            return isFenceAvailable(fenceMap.get(area.getElectronicId()));
        }
        if (Integer.valueOf(2).equals(point.getOperationType())
                && point.getEffectivePeriod() != null
                && StringUtils.isNotBlank(point.getEffectiveTimePeriod())) {
            return getInTime(LocalTime.now(), point.getEffectivePeriod(), point.getEffectiveTimePeriod());
        }
        return false;
    private boolean isPointAvailable(LocalTime localTime,  XpPoint point) {
        return bootCommonService.getPointOperation(localTime, point);
    }
    /**
     * 围栏生效判断:
     * 启用中,且当前时间需要落在生效时间与失效时间窗口内。
     */
    private boolean isFenceAvailable(XpElectronicFence fence) {
        if (fence == null || !Integer.valueOf(2).equals(fence.getStatus())) {
            return false;
        }
        LocalDateTime now = LocalDateTime.now();
        if (fence.getEffectTime() != null && now.isBefore(fence.getEffectTime())) {
            return false;
        }
        return !Integer.valueOf(2).equals(fence.getFailureType()) || fence.getFailureTime() == null || !now.isAfter(fence.getFailureTime());
    }
    /**
     * 组装单个场站子点位返回对象,并在有默认点位配置时打标。
@@ -881,4 +818,32 @@
        }
    }
    @Resource
    private TokenService tokenService;
    /**
     * 场站 失效-围栏失效 场站失效
     * @param electronicAreaIds
     */
    @Override
    public void setStatusFailure(List<Long> electronicAreaIds){
        if(CollUtil.isNotEmpty(electronicAreaIds)){
            LambdaQueryWrapper<XpPoint> query = new LambdaQueryWrapper<>();
            query.in(XpPoint::getElectronicAreaId, electronicAreaIds);
            query.eq(XpPoint::getDeleted, 0);
            List<XpPoint> list = super.list(query);
            if(!list.isEmpty()){
                LoginUser loginUser = tokenService.getLoginUser();
                for (XpPoint bean : list) {
                    bean.setUpdateBy(loginUser.getUsername());
                    bean.setUpdateTime(LocalDateTime.now());
                    bean.setOperationStatus(4);//场站状态 0=草稿 1=待启用 2=启用中 3=已停用 4=失效
                    boolean b = updateById(bean);
                }
            }
        }
    }
}