liujie
2026-06-09 c96fbe6b0aeb413a17c429133ee6d81d138144b9
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -10,20 +10,29 @@
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;
import com.mongodb.client.MongoCollection;
import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto;
import com.xiaopeng.api.dto.vehicleConvoy.ServiceVehicleListDto;
import com.xiaopeng.api.dto.vehicleConvoy.UpdateVehicleStateDto;
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.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.maintenance.XpVehicleRepair;
import com.xiaopeng.api.model.vehicleConvoy.XpFleetVehicle;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicleAnnualRecord;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.operation.VehiclePositionVo;
import com.xiaopeng.api.vo.vehicleConvoy.VehicleDoorStatusVo;
import com.xiaopeng.api.vo.vehicleConvoy.VehicleStateVo;
import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandCallbackVo;
import com.xiaopeng.common.core.domain.R;
@@ -31,14 +40,20 @@
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;
import com.xiaopeng.vehicleConvoy.constant.I18nKeyConstant;
import com.xiaopeng.vehicleConvoy.model.dto.*;
import com.xiaopeng.vehicleConvoy.model.exportExcel.XpVehicleExportExcel;
import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel;
import com.xiaopeng.vehicleConvoy.model.query.*;
import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO;
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;
@@ -50,17 +65,22 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
import org.apache.poi.ss.usermodel.Workbook;
import org.bson.Document;import org.springframework.beans.BeanUtils;
import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.i18n.LocaleContextHolder;
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.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -68,18 +88,13 @@
import java.io.*;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
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;
/**
 * <p>
@@ -112,6 +127,10 @@
    private final XpVehicleRepairClient xpVehicleRepairClient;
    private final AliOssService aliOssService;
    private final AliOssDownloadUtil aliOssDownloadUtil;
    @Resource
    private XpVehicleModelClient xpVehicleModelClient;
    /**
     * 根据ID列表批量查询车辆信息(内部接口)
     *
@@ -119,40 +138,43 @@
     * @return 车辆列表
     */
    @ApiOperation(value = "批量查询车辆信息", tags = {"内部接口"})
    @PostMapping("/inner/vehicle/listByIds")
    @PostMapping("/logan/inner/vehicle/listByIds")
    public R<List<XpVehicle>> listByIds(@RequestBody List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return R.ok(new ArrayList<>());
        }
        return R.ok(xpVehicleService.listByIds(ids));
    }
    /**
     * 批量获取车辆列表
     *
     * @return 车辆列表
     */
    @ApiOperation(value = "批量查询车辆信息", tags = {"内部接口"})
    @PostMapping("/inner/vehicle/listVehicle")
    @PostMapping("/logan/inner/vehicle/listVehicle")
    public R<List<XpVehicle>> listVehicle() {
        return R.ok(xpVehicleService.list());
    }
    /**
     * 根据ID查询车辆信息(内部接口)
     *
     * @param id 车辆ID
     * @return 车辆列表
     */
    @GetMapping("/inner/vehicle/queryById")
    @GetMapping("/logan/inner/vehicle/queryById")
    public R<XpVehicle> queryById(@RequestParam Long id) throws UnsupportedEncodingException {
        XpVehicle xpVehicle = xpVehicleService.getById(id);
        if (Objects.nonNull(xpVehicle)) {
            String vehiclePictures = xpVehicle.getVehiclePictures();
            if(vehiclePictures!=null){
            if (vehiclePictures != null) {
                JSONObject jsonObject = JSON.parseObject(vehiclePictures);
                // 1
                String downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
                jsonObject.put("url", downloadUrl);
//                String downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
//                jsonObject.put("url", downloadUrl);
                jsonObject.put("url", "");
                xpVehicle.setVehiclePictures(jsonObject.toJSONString());
            }
@@ -164,14 +186,15 @@
        }
        return R.ok(xpVehicle);
    }
    /**
     * 修改车辆信息(内部接口)
     *
     * @param xpVehicle 车辆信息
     * @return 车辆
     */
    @PostMapping("/inner/vehicle/updateVehicleById")
    public R<String> updateVehicleById(@RequestBody XpVehicle xpVehicle){
    @PostMapping("/logan/inner/vehicle/updateVehicleById")
    public R<String> updateVehicleById(@RequestBody XpVehicle xpVehicle) {
        xpVehicleService.updateById(xpVehicle);
        return R.ok();
    }
@@ -191,7 +214,7 @@
            appendRequestData = true
    )
    public R<?> addVehicle(@Valid @RequestBody VehicleAddDTO dto) {
        xpVehicleService.addVehicle(dto);
        xpVehicleService.addVehicle(dto, null);
        return R.ok();
    }
@@ -210,7 +233,7 @@
            appendRequestData = true
    )
    public R<?> editVehicle(@Valid @RequestBody VehicleEditDTO dto) {
        xpVehicleService.editVehicle(dto);
        xpVehicleService.editVehicle(dto, null);
        return R.ok();
    }
@@ -283,6 +306,7 @@
    public R<PageInfo<XpVehicle>> vehiclePageList(@RequestBody VehiclePageQuery query) {
        return R.ok(xpVehicleService.vehiclePageList(query));
    }
    /**
     * 导出在库车辆列表
     *
@@ -321,6 +345,7 @@
            }
        }
    }
    /**
     * 导入车辆
     *
@@ -501,6 +526,9 @@
        }
        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, buildVinQueryValues(vinSet))
@@ -595,6 +623,7 @@
            xpVehicleImportExcel.setVehiclePictures(getOssUrl(xpVehicleImportExcel.getVehiclePictures()));
        }
    }
    private String getOssUrl(String filePath) {
        try {
            // 获取到暂存的文件
@@ -611,6 +640,7 @@
        }
        return null;
    }
    /**
     * 导出在库车辆列表
     *
@@ -692,10 +722,10 @@
    @GetMapping("/api/v1/vehicle/queryById")
    public R<XpVehicle> getVehicleDetail(@ApiParam(value = "车辆id", required = true) @RequestParam Long id) throws UnsupportedEncodingException {
        XpVehicle vehicleDetail = xpVehicleService.getVehicleDetail(id);
        if(vehicleDetail.getVehiclePictures()!=null){
        if (vehicleDetail.getVehiclePictures() != null) {
            JSONObject jsonObject = JSONObject.parseObject(vehicleDetail.getVehiclePictures());
            String downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
            jsonObject.put("url",downloadUrl);
            jsonObject.put("url", downloadUrl);
            String jsonString = jsonObject.toJSONString();
            vehicleDetail.setVehiclePictures(jsonString);
        }
@@ -704,10 +734,11 @@
    /**
     * 删除在库车辆
     *
     * @param id
     * @return
     */
    @ApiOperation(value = "删除在库车辆",tags = {"管理后台-车辆管理-在库车辆管理"})
    @ApiOperation(value = "删除在库车辆", tags = {"管理后台-车辆管理-在库车辆管理"})
    @DeleteMapping("/api/v1/vehicle/delete/{id}")
    @AdminOperationLog(
            businessType = AdminBusinessType.STOCK_VEHICLE_MANAGEMENT,
@@ -815,52 +846,40 @@
    }
    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查询空闲车辆
     *
     */
    @GetMapping("/inner/vehicle/listByFenceId")
    public R<List<XpVehicle>> listByFenceId(@RequestParam("fenceId") Long fenceId){
    @GetMapping("/logan/inner/vehicle/listByFenceId")
    public R<List<XpVehicle>> listByFenceId(@RequestParam("fenceId") Long fenceId) {
        return R.ok(xpVehicleService.listByFenceId(fenceId));
    }
    @GetMapping("/logan/inner/vehicle/listAllByFenceId")
    public R<List<XpVehicle>> listAllByFenceId(@RequestParam("fenceId") Long fenceId) {
        return R.ok(xpVehicleService.listAllByFenceId(fenceId));
    }
    /**
     * 查询车辆位置信息 做筛选
     *
     * @param dto
     * @return
     */
    @PostMapping("/inner/vehicle/queryVehiclePositionByVin")
    @PostMapping("/logan/inner/vehicle/queryVehiclePositionByVin")
    public R<List<String>> queryVehiclePositionByVin(@RequestBody VehiclePositionByVinDto dto){
        List<XpVehicle> list = xpVehicleService.list(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, 0)
                .eq(XpVehicle::getOperatingStatus, 1).eq(XpVehicle::getVehicleType,2).eq(XpVehicle::getElectronicId, dto.getFenceId()).in(XpVehicle::getVehicleVin,
                buildVinQueryValues(dto.getVinList())));
        if(list.isEmpty()){
        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())
                .eq(XpVehicle::getVehicleType, 2).in(XpVehicle::getVehicleVin, buildVinQueryValues(dto.getVinList())));
        if (list.isEmpty()) {
            return R.ok(new ArrayList<>());
        }else {
        } 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);
        }
@@ -870,10 +889,11 @@
    /**
     * 查询车辆信息
     *
     * @param vehicleVin
     * @return
     */
    @GetMapping("/inner/vehicle/findByVehicleVin")
    @GetMapping("/logan/inner/vehicle/findByVehicleVin")
    public R<XpVehicle> findByVehicleVin(@RequestParam("vehicleVin") String vehicleVin){
        XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().in(XpVehicle::getVehicleVin, SensitiveDataCryptoUtil.queryValues(vehicleVin)));
@@ -890,22 +910,27 @@
    /**
     * 根据XPUID查询车辆信息
     *
     * @param xpuid
     * @return
     */
    @GetMapping("/inner/vehicle/findByVehicleXpuId")
    public R<XpVehicle> findByVehicleXpuId(@RequestParam("xpuid") String xpuid){
    @GetMapping("/logan/inner/vehicle/findByVehicleXpuId")
    public R<XpVehicle> findByVehicleXpuId(@RequestParam("xpuid") String xpuid) {
        XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getXpuId, xpuid));
        return R.ok(xpVehicle);
    }
    /**
     * 修改车辆状态
     *
     * @param updateVehicleStateDto
     * @return
     */
    @PostMapping("/inner/vehicle/updateVehicleStatus")
    public R<?> updateVehicleStatus(@RequestBody UpdateVehicleStateDto updateVehicleStateDto){
    @PostMapping("/logan/inner/vehicle/updateVehicleStatus")
    public R<?> updateVehicleStatus(@RequestBody UpdateVehicleStateDto updateVehicleStateDto) {
        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();
    }
@@ -913,11 +938,12 @@
    /**
     *
     * 查询车辆所属车队ID
     *
     * @param vehicleId
     * @return
     */
    @GetMapping("/inner/vehicle/findFleetIdByVehicleId")
    public R<Long> findFleetIdByVehicleId(@RequestParam Long vehicleId){
    @GetMapping("/logan/inner/vehicle/findFleetIdByVehicleId")
    public R<Long> findFleetIdByVehicleId(@RequestParam Long vehicleId) {
        XpFleetVehicle xpFleetVehicle = vehicleService.getOne(new LambdaQueryWrapper<XpFleetVehicle>().eq(XpFleetVehicle::getVehicleId, vehicleId));
        return R.ok(xpFleetVehicle.getFleetId());
    }
@@ -933,20 +959,21 @@
            @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataTypeClass = Long.class),
            @ApiImplicitParam(name = "orderType", value = "订单类型(1=用户单,2=测试单)", required = true, dataTypeClass = Integer.class)
    })
    public R<List<XpVehicle>> listAvailableVehicles(@RequestParam Long orderId, Integer orderType) {
        List<XpVehicle> list = xpVehicleService.listAvailableVehicles(orderId, orderType);
    public R<List<XpVehicleVO>> listAvailableVehicles(@RequestParam Long orderId, Integer orderType, String plateNumber, String fleetName) {
        List<XpVehicleVO> list = xpVehicleService.listAvailableVehicles(orderId, orderType,plateNumber,fleetName);
        return R.ok(list);
    }
    /**
     * 车辆控制消息回调通知
     * 开关门、设定温度
     *
     * @param callbackVo
     */
    @PostMapping("/base/vehicles/command/callback")
    public void vehiclesCommandCallback(@RequestBody VehiclesCommandCallbackVo callbackVo){
    public void vehiclesCommandCallback(@RequestBody VehiclesCommandCallbackVo callbackVo) {
        log.info("车辆控制消息回调:{}", JSON.toJSONString(callbackVo));
        if(null != callbackVo.getMsg_ref()){
        if (null != callbackVo.getMsg_ref()) {
            //继续执行业务逻辑上的代码
        }
    }
@@ -955,27 +982,31 @@
     * 车辆详情-车辆调度-接单、测试
     */
    @ApiOperation(value = "车辆详情", tags = {"运维APP-车辆管理"})
    @PostMapping("/api/v1/vehicle/vehicleDetail")
    @PostMapping("/maintenance-app/api/v1/vehicle/vehicleDetail")
    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);
        // 查询运维规则 保养周期
        XpTaskRule xpTaskRule = xpTaskRuleClient.queryDetail().getData();
        if(Objects.isNull(xpTaskRule)){
        if (Objects.isNull(xpTaskRule)) {
            return R.ok(xpVehicleVO);
        }
        Boolean maintenanceCycle = xpTaskRule.getMaintenanceCycle();
        Integer maintenanceCycleTime = xpTaskRule.getMaintenanceCycleTime();
        Integer maintenanceCycleTimeType = xpTaskRule.getMaintenanceCycleTimeType();
        if(maintenanceCycle){
        if (maintenanceCycle) {
            // 查询车辆上次保养记录
            XpTask xpTask = xpTaskClient.queryInfoByVehicleId(id).getData();
            if(Objects.nonNull(xpTask)){
            if (Objects.nonNull(xpTask)) {
                // 存在保养记录
                LocalDateTime handleTime = xpTask.getCreateTime();
                switch (maintenanceCycleTimeType){
                switch (maintenanceCycleTimeType) {
                    case 1:
                        handleTime.plusDays(maintenanceCycleTime);
                        break;
@@ -984,12 +1015,12 @@
                        break;
                }
                xpVehicleVO.setNextMaintenanceTime(handleTime.toLocalDate());
            }else {
            } else {
                // 没有保养记录
                // 入库时间
                LocalDateTime warehousingTime = xpVehicle.getWarehousingTime();
                if(Objects.nonNull(warehousingTime)){
                    switch (maintenanceCycleTimeType){
                if (Objects.nonNull(warehousingTime)) {
                    switch (maintenanceCycleTimeType) {
                        case 1:
                            warehousingTime.plusDays(maintenanceCycleTime);
                            break;
@@ -1002,11 +1033,12 @@
            }
        }
        // 查询车辆的续航里程
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicleVO.getVehicleVin())), VehiclePosition.class);
        if(Objects.nonNull(vehiclePosition)){
        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());
        }else {
        } else {
            xpVehicleVO.setMileageRange(0F);
            xpVehicleVO.setCurrentElectricity(0);
        }
@@ -1031,42 +1063,35 @@
    /**
     * 车辆管理-地图
     *
     * @return 车辆列表
     */
    @ApiOperation(value = "车辆管理-地图", tags = {"运维APP-车辆管理"})
    @PostMapping("/api/v1/vehicle/vehicleMap")
    @PostMapping("/maintenance-app/api/v1/vehicle/vehicleMap")
    public R<PageInfo<XpVehicleVO>> vehicleMap(@RequestBody VehicleMapQuery query) {
        Long operationsUserId = tokenService.getLoginOperationUser().getId();
        query.setOperationsUserId(operationsUserId);
        return R.ok(xpVehicleService.pageList(query));
    }
    /**
     * 根据车牌号查询车辆信息
     *
     * @param plateNumber
     * @return
     */
    @PostMapping("/inner/vehicle/listByPlateNumber")
    R<List<XpVehicle>> listByPlateNumber(@RequestParam("plateNumber") String plateNumber){
    @PostMapping("/logan/inner/vehicle/listByPlateNumber")
    R<List<XpVehicle>> listByPlateNumber(@RequestParam("plateNumber") String plateNumber) {
        return R.ok(xpVehicleService.listByPlateNumber(plateNumber));
    }
    /**
     * 车辆详情-车门解锁/后备箱解锁
     */
    @ApiOperation(value = "车辆运维-车门解锁/后备箱解锁", tags = {"运维APP-车辆管理"})
    @PostMapping("/api/v1/vehicle/unlockByType")
    public R<String> unlockByType(@RequestBody UnlockByTypeDTO dto) {
        // TODO 车门解锁、后备箱解锁
        return R.ok();
    }
    /**
     * 业务流程-车门解锁/后备箱解锁
     */
    @ApiOperation(value = "打开车门解锁/后备箱开关车门", tags = {"小程序-业务流程"})
    @PostMapping("/api/v1/mini-program/order/vehicle/unlock")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<Integer> unlock(@RequestBody UnlockAppletDTO dto) {
        return R.ok(xpVehicleService.unlock(dto));
    }
@@ -1076,6 +1101,7 @@
     */
    @ApiOperation(value = "打开设置温度", tags = {"小程序-业务流程"})
    @PostMapping("/api/v1/mini-program/order/ac/set-temperature")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<Integer> setTemperature(@RequestBody SetTemperatureDTO dto) {
        return R.ok(xpVehicleService.setTemperature(dto));
    }
@@ -1085,21 +1111,27 @@
     */
    @ApiOperation(value = "通过订单id查询当前车辆温度", tags = {"小程序-业务流程"})
    @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");
        return R.ok(hvacInnerTemp.getValue());
        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);
    }
@@ -1117,12 +1149,28 @@
    /**
     * 获取车辆不分页列表
     *
     * @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){
    public R<?> testUpdateVehicleStatus(@RequestBody UpdateVehicleStateDto updateVehicleStateDto) {
        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();
    }
@@ -1130,11 +1178,12 @@
    /**
     * 删除mongodb中的文档
     *
     * @param collectionName
     * @return
     */
    @PostMapping("/base/vi/removeMongodb")
    public R<?> removeMongodb(String collectionName){
    public R<?> removeMongodb(String collectionName) {
        MongoCollection<Document> collection = mongoTemplate.getCollection(collectionName);
        collection.drop();
        return R.ok();
@@ -1143,13 +1192,197 @@
    /**
     * 获取车辆后备箱开关状态
     *
     * @param uid
     * @param id
     * @return
     */
    @PostMapping("/inner/vi/vehicle/getVehicleTrunkOpenStatus")
    public R<Boolean> getVehicleTrunkOpenStatus(@RequestParam("uid") Long uid, @RequestParam("id") Long id){
        Boolean vehicleTrunkOpenStatus = xpVehicleService.getVehicleTrunkOpenStatus(uid, id);
    @PostMapping("/logan/inner/vi/vehicle/getVehicleTrunkOpenStatus")
    public R<Boolean> getVehicleTrunkOpenStatus(@RequestParam("uid") Long uid, @RequestParam("id") Long id) {
        Boolean vehicleTrunkOpenStatus = xpVehicleService.getVehicleTrunkOpenStatus(String.valueOf(uid), id);
        return R.ok(vehicleTrunkOpenStatus);
    }
    /**
     * 分页获取运营车辆列表
     * @param dto
     * @return
     */
    @PostMapping("/logan/inner/vehicle/getServiceVehicleList")
    public R<List<XpVehicle>> getServiceVehicleList(@RequestBody ServiceVehicleListDto dto){
        return R.ok(xpVehicleService.getServiceVehicleList(dto));
    }
    /**
     * 业务流程-车门解锁/后备箱解锁
     */
    @ApiOperation(value = "打开车门解锁/后备箱开关车门", tags = {"运维APP-车辆管理"})
    @PostMapping("/maintenance-app/api/v1/vehicle/unlockDoor")
    public R<Integer> unlockDoor(@RequestBody UnlockAppDTO dto) {
        XpOperationsUser xpOperationsUser = tokenService.getLoginOperationUser().getXpOperationsUser();
        return R.ok(xpVehicleService.unlockDoor(dto, xpOperationsUser));
    }
    @ApiOperation(value = "通过订单id查询当前车辆空调状态", tags = {"小程序-业务流程"})
    @GetMapping("/api/v1/mini-program/order/queryVehicleAirConditionerSwitch")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<Boolean> queryVehicleAirConditionerSwitch(@RequestParam Long orderId, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        Boolean hasKey = xpVehicleService.queryVehicleAirConditionerSwitch(orderId, uid);
        return R.ok(hasKey);
    }
    /**
     * 业务流程-车门解锁/后备箱解锁
     */
    @ApiOperation(value = "打开/关闭车内空调", tags = {"小程序-业务流程"})
    @PostMapping("/api/v1/mini-program/order/airConditionerUnlock")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<Integer> airConditionerUnlock(@RequestBody AirConditionerUnlockDTO dto, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        return R.ok(xpVehicleService.airConditionerUnlock(dto, uid));
    }
    /**
     * 根据订单id查询四门三盖状态
     * @param orderId
     * @return
     */
    @GetMapping("/logan/inner/vehicle/getVehicleDoorStatus/{orderId}")
    public R<VehicleDoorStatusVo> getVehicleDoorStatus(@PathVariable Long orderId){
        VehicleDoorStatusVo vehicleDoorStatus = xpVehicleService.getVehicleDoorStatus(orderId);
        return R.ok(vehicleDoorStatus);
    }
    /**
     * 周围车辆点位查询
     */
    @ApiOperation(value = "周围车辆点位查询", notes = "", tags = {"小程序-周围车辆点位查询"})
    @GetMapping("/api/v1/mini-program/vehicle/nearby")
    @XpClientCheck(checkToken = false, checkOtpToken = false)
    public R<List<XpVehicleVO>> carAround(@RequestParam double lon, @RequestParam double lat) {
        //找到中心点
        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()
                .map(vp -> {
                    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();
                    vo.setLongitude(vp.getPoint().getX());
                    vo.setLatitude(vp.getPoint().getY());
                    vo.setDirection(vp.getCourse());
                    vo.setId(xpVehicle.getId());
                    return vo;
                })
                .filter(Objects::nonNull)
                .limit(5)
                .collect(Collectors.toList());
        log.info("周围车辆筛选结果:{}", JSON.toJSONString(xpVehicleList));
        return R.ok(xpVehicleList);
    }
    @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();
    }
    /**
     * 根据车牌号查询数据
     * @param plateNumber
     * @param officialPartnerId
     * @return
     */
    @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);
    }
    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);
    }
}