liujie
2026-06-09 c96fbe6b0aeb413a17c429133ee6d81d138144b9
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -10,6 +10,7 @@
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.mongodb.client.MongoCollection;
import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto;
@@ -18,8 +19,13 @@
import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto;
import com.xiaopeng.api.feignClient.maintenance.*;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.account.XpOperationsUser;import com.xiaopeng.api.model.maintenance.XpTask;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.model.maintenance.XpErrorType;
import com.xiaopeng.api.model.maintenance.XpTask;
import com.xiaopeng.api.model.maintenance.XpTaskRule;
import com.xiaopeng.api.model.operation.XpGeoQueryEntity;
import com.xiaopeng.api.model.maintenance.XpVehicleModel;
import com.xiaopeng.api.model.operation.XpOfficialPartner;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
import com.xiaopeng.api.model.vehicleConvoy.XpFleetVehicle;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
@@ -31,8 +37,12 @@
import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandCallbackVo;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.SensitiveDataCryptoUtil;
import com.xiaopeng.common.core.utils.WebUtils;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.common.log.annotation.AdminOperationLog;
import com.xiaopeng.common.log.enums.AdminBusinessType;
import com.xiaopeng.common.log.enums.AdminOperationType;
import com.xiaopeng.common.security.service.TokenService;
import com.xiaopeng.evi.oss.service.AliOssService;
import com.xiaopeng.unifiedverification.interceptor.XpClientCheck;
@@ -42,6 +52,8 @@
import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel;
import com.xiaopeng.vehicleConvoy.model.query.*;
import com.xiaopeng.api.vo.vehicleConvoy.XpVehicleVO;
import com.xiaopeng.vehicleConvoy.model.vo.VehicleListByVinVo;
import com.xiaopeng.vehicleConvoy.model.vo.VehiclePositionDto;
import com.xiaopeng.vehicleConvoy.service.IXpFleetService;
import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService;
import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService;
@@ -58,11 +70,11 @@
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
@@ -78,6 +90,10 @@
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.xiaopeng.common.log.annotation.AdminOperationLog;
import com.xiaopeng.common.log.enums.AdminBusinessType;
import com.xiaopeng.common.log.enums.AdminOperationType;
import java.util.stream.Collectors;
/**
@@ -111,6 +127,9 @@
    private final XpVehicleRepairClient xpVehicleRepairClient;
    private final AliOssService aliOssService;
    private final AliOssDownloadUtil aliOssDownloadUtil;
    @Resource
    private XpVehicleModelClient xpVehicleModelClient;
    /**
     * 根据ID列表批量查询车辆信息(内部接口)
@@ -188,8 +207,14 @@
     */
    @ApiOperation(value = "新增车辆", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/add")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.ADD,
            content = "新增车辆",
            appendRequestData = true
    )
    public R<?> addVehicle(@Valid @RequestBody VehicleAddDTO dto) {
        xpVehicleService.addVehicle(dto);
        xpVehicleService.addVehicle(dto, null);
        return R.ok();
    }
@@ -201,8 +226,14 @@
     */
    @ApiOperation(value = "编辑车辆", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/edit")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.EDIT,
            content = "编辑车辆",
            appendRequestData = true
    )
    public R<?> editVehicle(@Valid @RequestBody VehicleEditDTO dto) {
        xpVehicleService.editVehicle(dto);
        xpVehicleService.editVehicle(dto, null);
        return R.ok();
    }
@@ -214,6 +245,12 @@
     */
    @ApiOperation(value = "完善/更新车辆信息", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/improveInfo")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.EDIT,
            content = "完善/更新车辆信息",
            appendRequestData = true
    )
    public R<?> improveInfo(@RequestBody VehicleImproveInfoDTO dto) {
        xpVehicleService.improveInfo(dto);
        return R.ok();
@@ -228,6 +265,12 @@
    @ApiOperation(value = "批量运营", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/batchOperation")
    @ApiImplicitParam(name = "idStr", value = "车辆ID字符串列表,逗号分隔", required = true, dataTypeClass = String.class)
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.EDIT,
            contentExpression = "'批量运营车辆,ids=' + #p0",
            appendRequestData = false
    )
    public R<?> batchOperation(@RequestParam String idStr) {
        xpVehicleService.batchOperation(idStr);
        return R.ok();
@@ -241,6 +284,12 @@
     */
    @ApiOperation(value = "批量设置运营区域", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/batchSetElectronic")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.EDIT,
            content = "批量设置运营区域",
            appendRequestData = true
    )
    public R<?> batchSetElectronic(@Valid @RequestBody VehicleBatchSetElectronicDTO dto) {
        xpVehicleService.batchSetElectronic(dto.getIds(), dto.getElectronicId());
        return R.ok();
@@ -264,6 +313,12 @@
     */
    @ApiOperation(value = "下载导入模板", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/importTemplate")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.EXPORT,
            content = "下载车辆导入模板",
            appendRequestData = false
    )
    public void importTemplate() {
        // 1. 查询导出数据
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), XpVehicleImportExcel.class, new ArrayList<>());
@@ -299,6 +354,12 @@
     */
    @ApiOperation(value = "导入", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/importExcel")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.IMPORT,
            content = "导入车辆",
            appendRequestData = false
    )
    public R<?> importExcel(@RequestParam("file") MultipartFile file) {
        ImportParams params = new ImportParams();
        params.setHeadRows(1);
@@ -465,12 +526,16 @@
        }
        Set<String> existsVins = Collections.emptySet();
        if (!vinSet.isEmpty()) {
            Set<String> vinQueryValues = vinSet.stream()
                    .flatMap(vin -> SensitiveDataCryptoUtil.queryValues(vin).stream())
                    .collect(java.util.stream.Collectors.toSet());
            existsVins = xpVehicleService.lambdaQuery()
                    .select(XpVehicle::getVehicleVin)
                    .in(XpVehicle::getVehicleVin, vinSet)
                    .in(XpVehicle::getVehicleVin, buildVinQueryValues(vinSet))
                    .list()
                    .stream()
                    .map(XpVehicle::getVehicleVin)
                    .map(SensitiveDataCryptoUtil::decryptIfPossible)
                    .filter(org.apache.commons.lang3.StringUtils::isNotBlank)
                    .collect(java.util.stream.Collectors.toSet());
        }
@@ -542,6 +607,17 @@
        return duplicated;
    }
    private static List<String> buildVinQueryValues(Iterable<String> vins) {
        if (vins == null) {
            return Collections.emptyList();
        }
        List<String> values = new ArrayList<>();
        for (String vin : vins) {
            values.addAll(SensitiveDataCryptoUtil.queryValues(vin));
        }
        return values.stream().distinct().collect(Collectors.toList());
    }
    private void uploadVehiclePicture(List<XpVehicleImportExcel> importList) {
        for (XpVehicleImportExcel xpVehicleImportExcel : importList) {
            xpVehicleImportExcel.setVehiclePictures(getOssUrl(xpVehicleImportExcel.getVehiclePictures()));
@@ -572,6 +648,12 @@
     */
    @ApiOperation(value = "导出", tags = {"管理后台-车辆管理-在库车辆管理"})
    @PostMapping("/api/v1/vehicle/exportExcel")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.EXPORT,
            content = "导出在库车辆",
            appendRequestData = true
    )
    public void exportExcel(@RequestBody VehicleExportQuery query) {
        // 1. 查询导出数据
        List<XpVehicle> dataList = xpVehicleService.vehicleExportList(query);
@@ -619,6 +701,12 @@
    @ApiOperation(value = "批量在库", tags = {"管理后台-车辆管理-运营车辆管理"})
    @ApiImplicitParam(name = "idStr", value = "车辆ID字符串列表,逗号分隔", required = true, dataTypeClass = String.class)
    @PostMapping("/api/v1/vehicle/batchStock")
    @AdminOperationLog(
            businessType = AdminBusinessType.OPERATION_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.EDIT,
            contentExpression = "'批量在库车辆,ids=' + #p0",
            appendRequestData = false
    )
    public R<?> batchStock(@RequestParam String idStr) {
        xpVehicleService.batchStock(idStr);
        return R.ok();
@@ -652,6 +740,12 @@
     */
    @ApiOperation(value = "删除在库车辆", tags = {"管理后台-车辆管理-在库车辆管理"})
    @DeleteMapping("/api/v1/vehicle/delete/{id}")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.DELETE,
            contentExpression = "'删除在库车辆,id=' + #p0",
            appendRequestData = false
    )
    public R<?> delete(@ApiParam(name = "id", value = "车辆ID") @PathVariable Long id) {
        XpFleetVehicle binding = vehicleService.lambdaQuery()
                .eq(XpFleetVehicle::getVehicleId, id)
@@ -693,6 +787,12 @@
     */
    @ApiOperation(value = "运营车辆管理列表导出", tags = {"管理后台-车辆管理-运营车辆管理"})
    @PostMapping("/api/v1/vehicle/operationExportExcel")
    @AdminOperationLog(
            businessType = AdminBusinessType.OPERATION_VEHICLE_MANAGEMENT,
            operationType = AdminOperationType.EXPORT,
            content = "导出运营车辆",
            appendRequestData = true
    )
    public void exportExcel(@RequestBody OperationVehicleExportQuery query) {
        // 1. 查询导出数据
        List<XpVehicle> dataList = xpVehicleService.operationVehicleExportList(query);
@@ -746,26 +846,7 @@
    }
    public static void main(String[] args) {
        String inspectionAttachments = "[{\"id\": \"d57c4ac4-acb0-451b-8e94-70f226331e0c\", \"url\": \"https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/552a3a31-e4dd-4a28-8748-fd8b87dd3055.png\", \"name\": \"测试.jpg\"}]";
        if (StringUtils.isNotBlank(inspectionAttachments)) {
            JSONArray jsonArray = JSONArray.parseArray(inspectionAttachments);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                if (Objects.isNull(jsonObject)) {
                    continue;
                }
                jsonObject.put("url", "downloadUrl");
            }
            String jsonString = JSONArray.toJSONString(jsonArray);
            System.out.println(jsonString);
        }
    }
    /**
     * 根据围栏id查询空闲车辆
@@ -790,14 +871,15 @@
    @PostMapping("/logan/inner/vehicle/queryVehiclePositionByVin")
    public R<List<String>> queryVehiclePositionByVin(@RequestBody VehiclePositionByVinDto dto){
        List<XpVehicle> list = xpVehicleService.list(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, Optional.ofNullable(dto.getStatus()).orElse(0))
                .eq(XpVehicle::getOperatingStatus, 1).eq(XpVehicle::getElectronicId, dto.getFenceId()).in(XpVehicle::getVehicleVin,
                dto.getVinList()));
                .eq(XpVehicle::getOperatingStatus, 1).eq(XpVehicle::getElectronicId, dto.getFenceId())
                .eq(XpVehicle::getVehicleType, 2).in(XpVehicle::getVehicleVin, buildVinQueryValues(dto.getVinList())));
        if (list.isEmpty()) {
            return R.ok(new ArrayList<>());
        } else {
            List<String> vehiclePositionVos = new ArrayList<>(list.size());
            for (XpVehicle xpVehicle : list) {
                vehiclePositionVos.add(xpVehicle.getVehicleVin());
                String vin = SensitiveDataCryptoUtil.decryptIfPossible(xpVehicle.getVehicleVin());
                vehiclePositionVos.add(vin);
            }
            return R.ok(vehiclePositionVos);
        }
@@ -812,15 +894,16 @@
     * @return
     */
    @GetMapping("/logan/inner/vehicle/findByVehicleVin")
    public R<XpVehicle> findByVehicleVin(@RequestParam("vehicleVin") String vehicleVin) {
        XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getVehicleVin, vehicleVin));
    public R<XpVehicle> findByVehicleVin(@RequestParam("vehicleVin") String vehicleVin){
        XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().in(XpVehicle::getVehicleVin, SensitiveDataCryptoUtil.queryValues(vehicleVin)));
        // 获取车队
        XpFleetVehicle xpFleetVehicle = vehicleService.getOne(new LambdaQueryWrapper<XpFleetVehicle>().eq(XpFleetVehicle::getVehicleId, xpVehicle.getId()));
        if(null == xpFleetVehicle){
            return R.fail("车队信息获取失败");
        if (Objects.nonNull(xpVehicle)) {
            XpFleetVehicle xpFleetVehicle = vehicleService.getOne(new LambdaQueryWrapper<XpFleetVehicle>().eq(XpFleetVehicle::getVehicleId, xpVehicle.getId()));
            if (Objects.nonNull(xpFleetVehicle)) {
                xpVehicle.setFleetId(xpFleetVehicle.getFleetId());
            }
        }
        xpVehicle.setFleetId(xpFleetVehicle.getFleetId());
        return R.ok(xpVehicle);
    }
@@ -845,7 +928,10 @@
     */
    @PostMapping("/logan/inner/vehicle/updateVehicleStatus")
    public R<?> updateVehicleStatus(@RequestBody UpdateVehicleStateDto updateVehicleStateDto) {
        xpVehicleService.update(new LambdaUpdateWrapper<XpVehicle>().eq(XpVehicle::getVehicleVin, updateVehicleStateDto.getVin()).set(XpVehicle::getState, updateVehicleStateDto.getState()));
        if (StringUtils.isBlank(updateVehicleStateDto.getVin())) {
            return R.ok();
        }
        xpVehicleService.update(new LambdaUpdateWrapper<XpVehicle>().in(XpVehicle::getVehicleVin, SensitiveDataCryptoUtil.queryValues(updateVehicleStateDto.getVin())).set(XpVehicle::getState, updateVehicleStateDto.getState()));
        return R.ok();
    }
@@ -900,6 +986,10 @@
    public R<XpVehicleVO> vehicleDetail(@RequestParam Long id) {
        // 查询车辆
        XpVehicle xpVehicle = xpVehicleService.getById(id);
        List<XpVehicleModel> vehicleModels = xpVehicleModelClient.listByIds(Arrays.asList(xpVehicle.getVehicleModel())).getData();
        if(null != vehicleModels && vehicleModels.size() > 0){
            xpVehicle.setVehicleModelName(vehicleModels.get(0).getName());
        }
        XpVehicleVO xpVehicleVO = new XpVehicleVO();
        BeanUtils.copyProperties(xpVehicle, xpVehicleVO);
        // 查询运维规则 保养周期
@@ -943,7 +1033,8 @@
            }
        }
        // 查询车辆的续航里程
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicleVO.getVehicleVin())), VehiclePosition.class);
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(xpVehicleVO.getVehicleVin());
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
        if (Objects.nonNull(vehiclePosition)) {
            xpVehicleVO.setMileageRange(vehiclePosition.getMileageRange());
            xpVehicleVO.setCurrentElectricity(vehiclePosition.getCurrentElectricity());
@@ -994,17 +1085,6 @@
        return R.ok(xpVehicleService.listByPlateNumber(plateNumber));
    }
    /**
     * 车辆详情-车门解锁/后备箱解锁
     */
    @ApiOperation(value = "车辆运维-车门解锁/后备箱解锁", tags = {"运维APP-车辆管理"})
    @PostMapping("/maintenance-app/api/v1/vehicle/unlockByType")
    public R<String> unlockByType(@RequestBody UnlockByTypeDTO dto) {
        // TODO 车门解锁、后备箱解锁
        return R.ok();
    }
    /**
     * 业务流程-车门解锁/后备箱解锁
@@ -1033,24 +1113,25 @@
    @GetMapping("/api/v1/mini-program/order/queryTemperatureByOrderId")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<String> queryTemperatureByOrderId(@RequestParam Long orderId, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
//        VehicleTemperatureDto vehicleTemperatureDto = xpVehicleService.queryTemperatureByOrderId(orderId, uid);
//        VehicleStateVo hvacInnerTemp = vehicleTemperatureDto.getStateMap().get("hvacInnerTemp");
//        if(null == hvacInnerTemp){
//            return R.fail("查询车内温度失败");
//        }
//        return R.ok(hvacInnerTemp.getValue());
        return R.ok("35.0");
        VehicleDoorStatusVo vehicleDoorStatus = xpVehicleService.getVehicleDoorStatus(orderId);
        if(null == vehicleDoorStatus){
            return R.fail("查询车内温度失败");
        }
        if(null == vehicleDoorStatus.getRearLeftHvacTempFloat()){
            return R.ok("25");
        }
        return R.ok(vehicleDoorStatus.getRearLeftHvacTempFloat().toString());
    }
    @ApiOperation(value = "通过订单id查询当前车辆车门状态", tags = {"小程序-业务流程"})
    @GetMapping("/api/v1/mini-program/order/queryVehicleTrunkOpenStatus")
    public R<VehicleTemperatureDto> queryVehicleTrunkOpenStatus(@RequestParam Long orderId, HttpServletRequest request) {
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<Integer> queryVehicleTrunkOpenStatus(@RequestParam Long orderId, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        VehicleTemperatureDto vehicleTemperatureDto = xpVehicleService.queryTemperatureByOrderId(orderId,uid);
        return R.ok(vehicleTemperatureDto);
        Boolean trunkOpenStatus = xpVehicleService.queryTrunkOpenStatusByOrderId(orderId, uid);
        return R.ok(trunkOpenStatus ? 1 : 0);
    }
@@ -1068,14 +1149,29 @@
    /**
     * 获取车辆不分页列表
     *
     * @param query
     * @return
     */
    @ApiOperation(value = "获取车辆分页列表", tags = {"管理后台-定向服务"})
    @PostMapping("/api/v1/vehicle/getTargetedVehiclePageList")
    public R<PageInfo<XpVehicleVO>> getTargetedVehiclePageList(@RequestBody VehicleSelectPageQuery query) {
        return R.ok(xpVehicleService.getTargetedVehiclePageList(query));
    }
    /**
     * 临时用于修改车辆接单状态
     *
     * @param updateVehicleStateDto
     * @return
     */
    @PostMapping("/base/vi/vehicle/updateVehicleStatus")
    public R<?> testUpdateVehicleStatus(@RequestBody UpdateVehicleStateDto updateVehicleStateDto) {
        xpVehicleService.update(new LambdaUpdateWrapper<XpVehicle>().eq(XpVehicle::getVehicleVin, updateVehicleStateDto.getVin()).set(XpVehicle::getState, updateVehicleStateDto.getState()));
        if (StringUtils.isBlank(updateVehicleStateDto.getVin())) {
            return R.ok();
        }
        xpVehicleService.update(new LambdaUpdateWrapper<XpVehicle>().in(XpVehicle::getVehicleVin, SensitiveDataCryptoUtil.queryValues(updateVehicleStateDto.getVin())).set(XpVehicle::getState, updateVehicleStateDto.getState()));
        return R.ok();
    }
@@ -1175,65 +1271,118 @@
    @GetMapping("/api/v1/mini-program/vehicle/nearby")
    @XpClientCheck(checkToken = false, checkOtpToken = false)
    public R<List<XpVehicleVO>> carAround(@RequestParam double lon, @RequestParam double lat) {
        Point point = new Point(lon, lat);
        Distance distance = new Distance(3, Metrics.KILOMETERS);
        Criteria criteria = Criteria.where("point")
                .nearSphere(point)
                .maxDistance(distance.getNormalizedValue());
        Query query = new Query(criteria);
        List<VehiclePositionVo> vehiclePositions = mongoTemplate.find(query, VehiclePositionVo.class);
        //找到中心点
        GeoJsonPoint geoJsonPoint = new GeoJsonPoint(lon, lat);
        //构造半径
        Distance distanceR = new Distance(3, Metrics.KILOMETERS);
        //画圆
        Circle circle = new Circle(geoJsonPoint, distanceR);
        // 构造query对象
        Query query = Query.query(Criteria.where("point").withinSphere(circle));
        List<VehiclePosition> vehiclePositions = mongoTemplate.find(query, VehiclePosition.class);
        if (CollectionUtils.isEmpty(vehiclePositions)) {
            return R.ok(new ArrayList<>());
        }
        log.info("周围车辆查询结果:{}", JSON.toJSONString(vehiclePositions));
        List<XpVehicleVO> xpVehicleList = vehiclePositions.stream()
                .sorted(Comparator.comparingDouble(VehiclePositionVo::getDistance))
                .map(vp -> {
                    XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getVehicleVin, vp.getVin()));
                    XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, 0).eq(XpVehicle::getOperatingStatus, 1)
                            .eq(XpVehicle::getAcceptOrTest, 1).eq(XpVehicle::getDeleted, 0).in(XpVehicle::getVehicleVin, SensitiveDataCryptoUtil.queryValues(vp.getVin())));
                    if (xpVehicle == null) {
                        return null;
                    }
                    XpVehicleVO vo = new XpVehicleVO();
                    BeanUtils.copyProperties(xpVehicle, vo);
                    vo.setLongitude(vp.getPoint().getX());
                    vo.setLatitude(vp.getPoint().getY());
                    vo.setDirection(vp.getCourse());
                    vo.setId(xpVehicle.getId());
                    return vo;
                })
                .filter(Objects::nonNull)
                .filter(v -> v.getState() != null && v.getState() == 0)
                .limit(5)
                .collect(Collectors.toList());
        log.info("周围车辆筛选结果:{}", JSON.toJSONString(xpVehicleList));
        return R.ok(xpVehicleList);
    }
    @ApiOperation(value = "上报车辆位置", notes = "", tags = {"流量接入-上报车辆位置"})
    @PostMapping("/api/v1/xp-rt/vehicle/position")
    public R<List<XpVehicleVO>> pushVehiclePosition(@RequestBody VehiclePosition vp) {
        // 更新到mongodb,用于被分配订单
        // 如果是接单中,更新导航路线
    @ApiOperation(value = "新增车辆", tags = {"流量接入-基础信息"})
    @PostMapping("/drainage/v1/vehicle/addVehicle")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "token", name = "token", required = true, paramType = "header")
    })
    public R<XpVehicle> addOfficialPartnerVehicle(@Valid @RequestBody VehicleAddDTO dto) {
        XpOfficialPartner officialPartner = tokenService.getOfficialPartner();
        XpVehicle vehicle = xpVehicleService.addVehicle(dto, officialPartner.getId());
        return R.ok(vehicle);
    }
    @PostMapping("/drainage/v1/vehicle/editVehicle")
    @ApiOperation(value = "编辑车辆", tags = {"流量接入-基础信息"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "token", name = "token", required = true, paramType = "header")
    })
    public R<?> editOfficialPartnerVehicle(@Valid @RequestBody VehicleEditDTO dto) {
        XpOfficialPartner officialPartner = tokenService.getOfficialPartner();
        xpVehicleService.editVehicle(dto, officialPartner.getId());
        return R.ok();
    }
    /**
     * 上报车辆实时位置信息
     * @param dto
     * @return
     */
    @PostMapping("/drainage/v1/vehicle/reportVehicleLocation")
    @ApiOperation(value = "上报车辆实时位置信息", notes = "流量接入-基础信息")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "token", name = "token", required = true, paramType = "header")
    })
    public R<?> reportVehicleLocation(@RequestBody VehiclePositionDto dto){
        XpOfficialPartner officialPartner = tokenService.getOfficialPartner();
        xpVehicleService.reportVehicleLocation(dto, officialPartner.getId());
        return R.ok();
    }
    /**
     * {@Link OrderStatusEnum}
     * @param vp
     * 根据车牌号查询数据
     * @param plateNumber
     * @param officialPartnerId
     * @return
     */
    @ApiOperation(value = "更新车辆状态", notes = "", tags = {"流量接入-更新车辆状态"})
    @PostMapping("/api/v1/xp-rt/vehicle/status")
    public R<List<XpVehicleVO>> pushVehicleStatus(@RequestBody VehiclePosition vp) {
    @PostMapping("/logan/inner/vehicle/getVehicleByPlateNumber")
    public R<XpVehicle> getVehicleByPlateNumber(@RequestParam("plateNumber") String plateNumber,
                                         @RequestParam("officialPartnerId") Integer officialPartnerId){
        XpVehicle vehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getPlateNumber, plateNumber).eq(XpVehicle::getOfficialPartnerId, officialPartnerId));
        return R.ok(vehicle);
    }
        // 前往接驾,等待上车,前往终点,到达终点等待下车,结束订单
        // 更新order状态
        return R.ok();
    private List<String> buildVinQueryValues(Set<String> vinList) {
        if (vinList == null || vinList.isEmpty()) {
            return java.util.Collections.emptyList();
        }
        return vinList.stream()
                .flatMap(vin -> SensitiveDataCryptoUtil.queryValues(vin).stream())
                .distinct()
                .collect(Collectors.toList());
    }
    @ApiOperation(value = "根据VIN码查询车辆信息", response = XpErrorType.class, tags = "远程代驾")
    @GetMapping("/logan/assistance/v1/vehicle/getVehicleListByVin/{vin}")
    public R<VehicleListByVinVo> getVehicleListByVin(@PathVariable String vin) {
        XpVehicle vehicle = xpVehicleService.getOne(new QueryWrapper<XpVehicle>().eq("vehicle_vin", SensitiveDataCryptoUtil.encrypt(vin))
                .eq("is_deleted", 0));
        VehicleListByVinVo vehicleListByVinVo = new VehicleListByVinVo();
        BeanUtil.copyProperties(vehicle, vehicleListByVinVo);
        vehicleListByVinVo.setVin(vin);
        return R.ok(vehicleListByVinVo);
    }
}