RiderLocationServiceImpl.java 7.39 KB
package com.diligrp.rider.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.diligrp.rider.dto.DeliveryPricingConfigDTO;
import com.diligrp.rider.dto.LocationDTO;
import com.diligrp.rider.entity.Rider;
import com.diligrp.rider.entity.RiderLocation;
import com.diligrp.rider.mapper.RiderLocationMapper;
import com.diligrp.rider.mapper.RiderMapper;
import com.diligrp.rider.service.CityService;
import com.diligrp.rider.service.RiderLocationService;
import com.diligrp.rider.util.GeoUtil;
import com.diligrp.rider.vo.AdminRiderLocationVO;
import com.diligrp.rider.vo.NearbyRiderVO;
import com.diligrp.rider.websocket.LocationPushService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
@Slf4j
public class RiderLocationServiceImpl implements RiderLocationService {

    private static final long ACTIVE_WINDOW_SECONDS = 300;

    private final RiderLocationMapper locationMapper;
    private final RiderMapper riderMapper;
    private final CityService cityService;
    private final LocationPushService locationPushService;

    /**
     * 按骑手维度更新最新位置。
     */
    @Override
    public void updateLocation(Long riderId, LocationDTO dto) {
        long now = System.currentTimeMillis() / 1000;
        log.debug("更新骑手位置,参数 riderId={} lng={} lat={} updateTime={}",
                riderId, dto.getLng(), dto.getLat(), now);
        Rider rider = riderMapper.selectById(riderId);
        locationMapper.upsertLocation(
                riderId,
                dto.getLng().stripTrailingZeros().toPlainString(),
                dto.getLat().stripTrailingZeros().toPlainString(),
                now);
        if (rider != null && rider.getCityId() != null) {
            AdminRiderLocationVO location = new AdminRiderLocationVO();
            location.setRiderId(riderId);
            location.setRiderName(rider.getUserNickname());
            location.setCityId(rider.getCityId());
            location.setLng(dto.getLng());
            location.setLat(dto.getLat());
            location.setUpdateTime(now);
            locationPushService.pushRiderLocation(location);
        }
    }

    /**
     * 查询当前骑手最近一次上报的位置。
     */
    @Override
    public LocationDTO getLocation(Long riderId) {
        log.debug("查询骑手当前位置,参数 riderId={}", riderId);
        RiderLocation loc = locationMapper.selectOne(new LambdaQueryWrapper<RiderLocation>()
                .eq(RiderLocation::getUid, riderId));
        if (loc == null) {
            log.debug("未查询到骑手位置,riderId={}", riderId);
            return null;
        }
        LocationDTO dto = new LocationDTO();
        dto.setLng(new BigDecimal(loc.getLng()));
        dto.setLat(new BigDecimal(loc.getLat()));
        return dto;
    }

    @Override
    public List<AdminRiderLocationVO> listActiveByCity(Long cityId) {
        List<AdminRiderLocationVO> result = new ArrayList<>();
        if (cityId == null || cityId < 1) {
            return result;
        }

        List<Rider> riders = riderMapper.selectList(new LambdaQueryWrapper<Rider>()
                .eq(Rider::getCityId, cityId)
                .eq(Rider::getIsRest, 0)
                .eq(Rider::getUserStatus, 1));
        if (riders.isEmpty()) {
            return result;
        }

        List<Long> riderIds = riders.stream().map(Rider::getId).toList();
        long minUpdateTime = System.currentTimeMillis() / 1000 - ACTIVE_WINDOW_SECONDS;
        List<RiderLocation> locations = locationMapper.selectList(
                new LambdaQueryWrapper<RiderLocation>()
                        .in(RiderLocation::getUid, riderIds)
                        .ge(RiderLocation::getUpdateTime, minUpdateTime));
        if (locations.isEmpty()) {
            return result;
        }

        java.util.Map<Long, Rider> riderMap = riders.stream()
                .collect(java.util.stream.Collectors.toMap(Rider::getId, rider -> rider));
        for (RiderLocation location : locations) {
            Rider rider = riderMap.get(location.getUid());
            if (rider == null) {
                continue;
            }
            try {
                AdminRiderLocationVO vo = new AdminRiderLocationVO();
                vo.setRiderId(rider.getId());
                vo.setRiderName(rider.getUserNickname());
                vo.setCityId(rider.getCityId());
                vo.setLng(new BigDecimal(location.getLng()));
                vo.setLat(new BigDecimal(location.getLat()));
                vo.setUpdateTime(location.getUpdateTime());
                result.add(vo);
            } catch (Exception ignored) {
            }
        }
        log.debug("查询城市活跃骑手位置完成,cityId={} count={}", cityId, result.size());
        return result;
    }

    /**
     * 查询城市范围内最近活跃的附近骑手。
     */
    @Override
    public List<NearbyRiderVO> getNearby(Long cityId, BigDecimal lng, BigDecimal lat) {
        List<NearbyRiderVO> result = new ArrayList<>();
        log.debug("开始查询附近骑手,参数 cityId={} lng={} lat={}", cityId, lng, lat);
        if (cityId == null || cityId < 1 || lng == null || lat == null) {
            return result;
        }

        DeliveryPricingConfigDTO config = cityService.getConfig(cityId);
        if (config == null) {
            return result;
        }
        BigDecimal limitKm = config.getRiderDistance();
        if (limitKm == null || limitKm.compareTo(BigDecimal.ZERO) <= 0) {
            limitKm = BigDecimal.valueOf(3);
        }

        List<Rider> riders = riderMapper.selectList(new LambdaQueryWrapper<Rider>()
                .eq(Rider::getCityId, cityId)
                .eq(Rider::getIsRest, 0)
                .eq(Rider::getUserStatus, 1));
        if (riders.isEmpty()) {
            log.debug("当前城市没有在线骑手,cityId={}", cityId);
            return result;
        }

        List<Long> riderIds = riders.stream().map(Rider::getId).toList();
        long minUpdateTime = System.currentTimeMillis() / 1000 - ACTIVE_WINDOW_SECONDS;
        List<RiderLocation> locations = locationMapper.selectList(
                new LambdaQueryWrapper<RiderLocation>()
                        .in(RiderLocation::getUid, riderIds)
                        .ge(RiderLocation::getUpdateTime, minUpdateTime));

        double queryLat = lat.doubleValue();
        double queryLng = lng.doubleValue();
        double limitD = limitKm.doubleValue();

        for (RiderLocation loc : locations) {
            try {
                double dist = GeoUtil.calcDistanceKm(
                        queryLat, queryLng,
                        Double.parseDouble(loc.getLat()),
                        Double.parseDouble(loc.getLng()));
                if (dist <= limitD) {
                    NearbyRiderVO vo = new NearbyRiderVO();
                    vo.setLng(loc.getLng());
                    vo.setLat(loc.getLat());
                    vo.setDistance(dist);
                    result.add(vo);
                }
            } catch (Exception ignored) {
            }
        }
        log.debug("附近骑手查询完成,cityId={} 在线骑手数={} 位置记录数={} 命中数={}",
                cityId, riders.size(), locations.size(), result.size());
        return result;
    }
}