puzhibing
2026-04-18 93159eb7cd97fdca5ec832a4056c0d5222536929
新增加运维APP解锁车门接口
1个文件已添加
5个文件已修改
176 ■■■■■ 已修改文件
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/vehicleConvoy/BluetoothUnlockClient.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/dto/ServiceNameConstantsEnum.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/model/dto/UnlockAppDTO.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/vehicleConvoy/BluetoothUnlockClient.java
@@ -13,9 +13,8 @@
/**
 * 蓝牙解锁车门
 */
// todo 需要修改蓝牙微服务调用名
@FeignClient(contextId = "BluetoothUnlockClient",
        value = ServiceNameConstantsEnum.XP_VEHICLE_USER_SERVICE,
        value = ServiceNameConstantsEnum.XP_SMART_DIGITAL_KEY_BOOT,
        fallbackFactory = UserVehicleClientFallbackFactory.class)
public interface BluetoothUnlockClient {
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/dto/ServiceNameConstantsEnum.java
@@ -69,5 +69,9 @@
     * 小鹏短信服务
     */
    String XP_NOTIFY_BOOT = "xp-notify-boot";
    /**
     * 小鹏数字秘钥服务
     */
    String XP_SMART_DIGITAL_KEY_BOOT = "xp-smart-digital-key-boot";
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -18,7 +18,7 @@
import com.xiaopeng.api.dto.vehicleConvoy.UpdateVehicleStateDto;
import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto;
import com.xiaopeng.api.feignClient.maintenance.*;
import com.xiaopeng.api.model.maintenance.XpTask;
import com.xiaopeng.api.model.account.XpOperationsUser;import com.xiaopeng.api.model.maintenance.XpTask;
import com.xiaopeng.api.model.maintenance.XpTaskRule;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
import com.xiaopeng.api.model.vehicleConvoy.XpFleetVehicle;
@@ -1108,4 +1108,17 @@
    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));
    }
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/model/dto/UnlockAppDTO.java
New file
@@ -0,0 +1,25 @@
package com.xiaopeng.vehicleConvoy.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "运维APP-车辆解锁车门、后备箱")
public class UnlockAppDTO implements Serializable {
    @ApiModelProperty("车辆id")
    private Long vehicleId;
    @ApiModelProperty(value = "要开启的车门类型,取值: \"door\" — 主副驾车门 \"trunk\" — 后备箱")
    private String doorType;
    @ApiModelProperty(value = "用户经度")
    private Double longitude;
    @ApiModelProperty(value = "用户纬度")
    private Double latitude;
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiaopeng.api.dto.vehicleConvoy.ServiceVehicleListDto;
import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.vehicleConvoy.model.dto.*;
@@ -209,4 +210,12 @@
     * @return
     */
    List<XpVehicle> getServiceVehicleList(ServiceVehicleListDto dto);
    /**
     * 运维APP解锁车门和开关后备箱
     * @param dto
     * @return
     */
    Integer unlockDoor(UnlockAppDTO dto, XpOperationsUser xpOperationsUser);
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -11,9 +11,11 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableMap;
import com.xiaopeng.api.dto.account.UcUserInfo;
import com.xiaopeng.api.dto.pushMessage.SendMessageDTO;
import com.xiaopeng.api.dto.vehicleConvoy.ServiceVehicleListDto;
import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto;
import com.xiaopeng.api.feignClient.account.UserResourcesClient;
import com.xiaopeng.api.feignClient.automaticPilot.XpuVinClient;
import com.xiaopeng.api.feignClient.map.AdcFencePushClient;
import com.xiaopeng.api.feignClient.operation.XpElectronicClient;
@@ -21,6 +23,8 @@
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.order.XpTestOrderClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpElectronicFenceArea;
import com.xiaopeng.api.model.order.XpOrder;
@@ -28,9 +32,7 @@
import com.xiaopeng.api.model.vehicleConvoy.*;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.operation.ElectronicFenceDetailVo;
import com.xiaopeng.api.vo.vehicleConvoy.VehicleStateVo;import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandEnum;
import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandParamVo;
import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandVo;
import com.xiaopeng.api.vo.vehicleConvoy.*;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.OrderStatusEnum;
@@ -127,11 +129,20 @@
    @Autowired(required = false)
    private AdcFencePushClient adcFencePushClient;
    @Resource
    private UserVehicleClient userVehicleClient;
    @Resource
    private UserResourcesClient userResourcesClient;
    @Value("${vehicle.control.distance-threshold:100}")
    private int distanceThreshold;
    @Value("${vehicle.control.report.enable:true}")
    private boolean reportEnable;
    @Value("${robotaxi.appId:xp_robotaxi_api}")
    private String appid;
    @Override
    public List<XpVehicle> listByIds(List<Long> ids) {
@@ -1121,6 +1132,7 @@
    /**
     * 获取服务车辆列表
     *
     * @param dto
     * @return
     */
@@ -1135,4 +1147,106 @@
        return list;
    }
    /**
     * 运维APP解锁车门和开关后备箱
     *
     * @param dto
     * @return
     */
    @Override
    public Integer unlockDoor(UnlockAppDTO dto, XpOperationsUser xpOperationsUser) {
        XpVehicle xpVehicle = this.getById(dto.getVehicleId());
        // 判断距离是否在范围之内 15米
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
        if (Objects.nonNull(vehiclePosition)) {
            GeoJsonPoint point = vehiclePosition.getPoint();
            if (Objects.nonNull(point)) {
                Map<String, Double> distance = GeodesyUtil.getDistance(dto.getLongitude() + "," + dto.getLatitude(), point.getX() + "," + point.getY());
                if (null != distance) {
                    Double distance1 = distance.get("WGS84");
                    if (distance1 > distanceThreshold) {
                        log.info("距离过远,无法打开 {} {} {}", dto.getLongitude() + "," + dto.getLatitude(), point.getX() + "," + point.getY(), distance1);
                        throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
                    }
                } else {
                    log.info("计算距离失败,无法打开车门");
                    throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
                }
            } else {
                log.info("车辆无实时定位,无法打开车门");
                throw new ServiceException("距离过远,无法打开", I18nKeyConstant.VEHICLE_DISTANCE_TOO_LONG);
            }
        }
        //先将运维人员和车辆绑定
        String phoneNumber = xpOperationsUser.getPhoneNumber();
        UcUserInfo userByMobile = userResourcesClient.getUserByMobile(phoneNumber);
        Long uid = userByMobile.getUid();
        AddTaxiPassengerVo addVo = new AddTaxiPassengerVo();
        addVo.setVin(xpVehicle.getVehicleVin());
        addVo.setUid(userByMobile.getUid().toString());
        addVo.setOrderNo(phoneNumber);
        addVo.setAppId(appid);
        userVehicleClient.addTaxiPassenger(addVo);
        log.info("已绑定运维与新车辆关系,电话号码: {}, VIN: {}", phoneNumber, xpVehicle.getVehicleVin());
        try {
            // 车门解锁、后备箱解锁
            VehiclesCommandVo vehiclesCommandVo = new VehiclesCommandVo();
            vehiclesCommandVo.setVin(xpVehicle.getVehicleVin());
            if ("door".equals(dto.getDoorType())) {
                // 开启车门 判断是否为P档
                Integer gearLevel = redisService.getCacheObject(CacheConstants.GEAR_LEVEL + xpVehicle.getXpuId());
                log.info("开启车门当前车辆档位: {} {}", xpVehicle.getXpuId(), gearLevel);
                if (gearLevel == null || gearLevel != 4) {
                    throw new ServiceException("车辆非P档,无法开启车门", I18nKeyConstant.VEHICLE_NOT_P_GEAR);
                }
                vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_UNLOCK.getCommand());
            } else {
                // 开启后备箱 判断是否为P档
                Integer gearLevel = redisService.getCacheObject(CacheConstants.GEAR_LEVEL + xpVehicle.getXpuId());
                log.info("开启后备箱当前车辆档位: {} {}", xpVehicle.getXpuId(), gearLevel);
                if (gearLevel == null || gearLevel != 4) {
                    throw new ServiceException("车辆非P档,无法操作后备箱", I18nKeyConstant.VEHICLE_NOT_P_GEAR);
                }
                //查询后备箱开关状态(打开状态=true,关闭状态=false)
                Boolean hasKey = vehicleControlUtil.queryTrunkDoorStateSync(uid, xpVehicle.getVehicleVin(), reportEnable);
                //打开状态
                if (hasKey) {
                    vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_CLOSE.getCommand());
                } else {
                    //关闭状态
                    vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_OPEN.getCommand());
                }
            }
            // {
            //    "code": 0,
            //    "data": {
            //        "msgId": "1234556"
            //    },
            //    "msg": "",
            //    "desc": "成功"
            //}
            String msgId = vehicleControlUtil.vehiclesCommand(vehiclesCommandVo, uid);
            log.info("车辆控制结果:{}", msgId);
            if (StringUtils.isEmpty(msgId)) {
                return 0;
            } else {
                return 1;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //解绑运维与车辆的绑定关系
            CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo();
            cancelTaxiPassengerVo.setVin(xpVehicle.getVehicleVin());
            cancelTaxiPassengerVo.setUid(userByMobile.getUid().toString());
            cancelTaxiPassengerVo.setOrderNo(phoneNumber);
            cancelTaxiPassengerVo.setAppId(appid);
            userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
        }
        return 0;
    }
}