puzhibing
2026-04-22 900f2e86e31b45239cef7e3e46ee5c2541a9eb99
Merge remote-tracking branch 'origin/1.0' into 1.0

# Conflicts:
# xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
2 文件已重命名
1个文件已添加
34个文件已修改
510 ■■■■■ 已修改文件
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpCheckLocation.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/query/operation/XpStationQuery.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/automaticPilot/VehiclePosition.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/NearestNextVo.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/VehiclePositionVo.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/vehicleConvoy/XpVehicleVO.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/utils/GeodesyUtil.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/controller/ActiveOrderController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpCheckLocationController.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpVehicleModelController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/mapper/XpTaskMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/query/XpCheckLocationQuery.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpCheckLocationMapper.xml 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpCruiseCheckInRecordMapper.xml 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpPointManagementController.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpStationService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpPointServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpStationServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpOpenCityController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/NearestVo.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mapper/XpOrderMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/webSocket/handler/PositionMsgHandler.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/webSocket/handler/TestMsgHandler.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/webSocket/handler/WebSocketTextFrameHandler.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/mapper/XpVehicleMapper.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/model/query/VehicleMapQuery.java 11 ●●●●● 补丁 | 查看 | 原始文档 | 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 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/resources/mapper/vehicleConvoy/XpVehicleMapper.xml 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpCheckLocation.java
@@ -47,4 +47,7 @@
    @ApiModelProperty(value = "状态 1=启用 0=禁用")
    private Integer status;
    @ApiModelProperty(value = "状态 1=上班打卡 0=巡游打卡")
    private Integer type = 1;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/query/operation/XpStationQuery.java
@@ -14,6 +14,8 @@
    @ApiModelProperty(value = "场站名称编码")
    private String stationNameOrNumber;
    @ApiModelProperty(value = "点位经纬度")
    private String pointLonAndLat;
    @ApiModelProperty(value = "场站状态 0=草稿 1=待启用 2=启用中 3=已停用 4=失效")
    private Integer status;
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/automaticPilot/VehiclePosition.java
@@ -2,7 +2,6 @@
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.CompoundIndexes;
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/NearestNextVo.java
File was renamed from xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/NearestNextVo.java
@@ -1,4 +1,4 @@
package com.xiaopeng.operation.vo;
package com.xiaopeng.api.vo.operation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/VehiclePositionVo.java
@@ -70,6 +70,10 @@
     */
    private Integer timeScore=0;
    /**
     * 航向,单位:度,北零顺时针。范围:[0-360)。0 => 北, 90 => 东, 180 => 南, 270 => 西
     */
    private Double course;
    /**
     * 价值分数
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/vehicleConvoy/XpVehicleVO.java
File was renamed from xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/model/vo/XpVehicleVO.java
@@ -1,4 +1,4 @@
package com.xiaopeng.vehicleConvoy.model.vo;
package com.xiaopeng.api.vo.vehicleConvoy;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
@@ -36,4 +36,7 @@
    @ApiModelProperty(value = "车辆维修状态 1=取回 2=送修")
    private Integer maintenanceStatus;
    @ApiModelProperty(value = "方向角度")
    private Double direction;
}
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/utils/GeodesyUtil.java
@@ -57,7 +57,7 @@
    }
    private static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid){
    public static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid){
        //创建GeodeticCalculator,调用计算方法,传入坐标系、经纬度用于计算距离
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo);
        return geoCurve.getEllipsoidalDistance();
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/controller/ActiveOrderController.java
@@ -2,8 +2,11 @@
import com.xiaopeng.api.dto.map.RouteAndFareDto;
import com.xiaopeng.api.dto.order.OrderChangeDto;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.operation.RouteAndFareVo;
import com.xiaopeng.api.vo.operation.VehiclePositionVo;
import com.xiaopeng.api.vo.vehicleConvoy.XpVehicleVO;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.itinerary.service.ActiveOrderService;
import com.xiaopeng.itinerary.service.XpPricingService;
@@ -11,6 +14,7 @@
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
@@ -23,7 +27,9 @@
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
@@ -76,24 +82,7 @@
        return R.ok();
    }
    /**
     * 周围车辆点位查询
     */
    @ApiOperation(value = "周围车辆点位查询", notes = "", tags = {"小程序-周围车辆点位查询"})
    @GetMapping("/api/v1/mini-program/nearby/cars")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<List<VehiclePosition>> carAround(@RequestParam double lon,@RequestParam double lat,@RequestParam double distanceMeters,HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        Point point = new Point(lon, lat);
        Distance distance = new Distance(distanceMeters / 1000.0, Metrics.KILOMETERS);
        Criteria criteria = Criteria.where("point")
                .nearSphere(point)
                .maxDistance(distance.getNormalizedValue());
        Query query = new Query(criteria);
        return R.ok(mongoTemplate.find(query, VehiclePosition.class));
    }
    @Resource
    private MongoTemplate mongoTemplate;
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpCheckLocationController.java
@@ -2,7 +2,6 @@
import cn.hutool.core.collection.CollUtil;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.maintenance.XpCheckLocation;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.DisabledEnum;
@@ -13,7 +12,6 @@
import com.xiaopeng.maintenance.service.IXpCheckLocationService;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -27,7 +25,7 @@
 */
@Validated
@RestController
@RequiredArgsConstructor(onConstructor_ = @Lazy)
@RequiredArgsConstructor
public class XpCheckLocationController {
    private final IXpCheckLocationService xpCheckLocationService;
    private final XpFleetClient xpFleetClient;
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpVehicleModelController.java
@@ -30,7 +30,7 @@
    private XpPricingClient xpPricingClient;
    @ApiOperation(value = "分页列表", tags = "管理后台-分页列表")
    @ApiOperation(value = "车型分页列表", tags = "管理后台-资产-车型管理")
    @PostMapping("/logan/inner/xpVehicleModel/pageList")
    public R<PageInfo<XpVehicleModel>> pageList(@RequestBody XpVehicleModelPageQuery query) {
        PageInfo<XpVehicleModel> pageInfo = xpVehicleModelService.pageList(query);
@@ -39,7 +39,7 @@
    @PostMapping("/logan/inner/xpVehicleModel/listByIds")
    @ApiOperation(value = "根据ID列表批量查询", tags = {"内部接口"})
    @ApiOperation(value = "车型根据ID列表批量查询", tags = {"内部接口"})
    public R<List<XpVehicleModel>> listByIds(@RequestBody List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return R.ok(new ArrayList<>());
@@ -48,7 +48,7 @@
    }
    @ApiOperation(value = "根据ID查询", tags = "管理后台-车型根据ID查询")
    @ApiOperation(value = "车型根据ID查询", tags = "管理后台-资产-车型管理")
    @GetMapping("/logan/inner/xpVehicleModel/getById")
    public R<XpVehicleModel> getById(@RequestParam String id) {
        if (id == null || id.isEmpty()) {
@@ -62,7 +62,7 @@
    }
    
    
    @ApiOperation(value = "新增", tags = "管理后台-车型新增")
    @ApiOperation(value = "车型新增", tags = "管理后台-资产-车型管理")
    @PostMapping("/logan/inner/xpVehicleModel/add")
    public R<String> add(@RequestBody @Valid XpVehicleModel dto) {
        // 根据名称查询车辆型号,验证是否已存在
@@ -77,7 +77,7 @@
        return R.fail("保存失败");
    }
    @ApiOperation(value = "编辑", tags = "管理后台-车型编辑")
    @ApiOperation(value = "车型编辑", tags = "管理后台-资产-车型管理")
    @PostMapping("/logan/inner/xpVehicleModel/edit")
    public R<String> edit(@RequestBody @Valid XpVehicleModel dto) {
        if(dto.getId() == null){
@@ -100,7 +100,7 @@
        return R.fail("保存失败");
    }
    @ApiOperation(value = "删除", tags = "管理后台-车型删除")
    @ApiOperation(value = "车型删除", tags = "管理后台-资产-车型管理")
    @DeleteMapping("/logan/inner/xpVehicleModel/deleteById")
    public R<String> deleteById(@RequestParam String id) {
        /*
@@ -126,7 +126,7 @@
    }
    
    @ApiOperation(value = "全列表查询", tags = "管理后台-车型全列表查询")
    @ApiOperation(value = "车型全列表查询", tags = "管理后台-车型全列表查询")
    @PostMapping("/logan/inner/xpVehicleModel/list")
    public R<List<XpVehicleModel>> list() {
        List<XpVehicleModel> list = xpVehicleModelService.queryList();
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/mapper/XpTaskMapper.java
@@ -39,5 +39,5 @@
     */
    XpTask queryInfoByVehicleId(@Param("vehicleId")Long vehicleId);
    PageInfo<TaskVO> reassignTaskPageList(TaskPageListQuery query);
    PageInfo<TaskVO> reassignTaskPageList(@Param("pageInfo")PageInfo<TaskPageListQuery> pageInfo, @Param("query")TaskPageListQuery query);
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/query/XpCheckLocationQuery.java
@@ -12,4 +12,7 @@
    @ApiModelProperty(value = "打卡地址")
    private String locationAddress;
    @ApiModelProperty(value = "状态 1=上班打卡 2=巡游打卡")
    private Integer type = 1;
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
@@ -25,6 +25,7 @@
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.model.account.XpOperationsUserNotification;
import com.xiaopeng.api.model.maintenance.*;
import com.xiaopeng.api.model.operation.XpPasswordFreePolicy;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.TaskVO;
import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO;
@@ -1501,7 +1502,9 @@
    @Override
    public PageInfo<TaskVO> reassignTaskPageList(TaskPageListQuery query) {
        return baseMapper.reassignTaskPageList(query);
        // 创建分页对象
        PageInfo<TaskPageListQuery> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        return baseMapper.reassignTaskPageList(pageInfo,query);
    }
    @Value("${robotaxi.sms.app-id:1476153389173952512}")
xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpCheckLocationMapper.xml
@@ -10,6 +10,7 @@
                and location_address like concat('%',#{query.locationAddress},'%')
            </if>
            AND is_deleted = 0
            AND type = #{query.type}
        </where>
        order by create_time desc
    </select>
xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpCruiseCheckInRecordMapper.xml
@@ -42,10 +42,10 @@
            r.scene_photo,
            r.scene_description
        FROM xp_cruise_check_in_record r
        LEFT JOIN xp_operations_user u ON r.operations_user_id = u.id AND u.del_flag = '0'
        LEFT JOIN xp_check_location cl ON r.check_location_id = cl.id AND cl.del_flag = '0'
        LEFT JOIN xp_cruise_check_in_rule cr ON r.cruise_check_in_rule_id = cr.id AND cr.del_flag = '0'
        WHERE r.del_flag = '0'
        LEFT JOIN xp_operations_user u ON r.operations_user_id = u.id AND u.is_deleted = '0'
        LEFT JOIN xp_check_location cl ON r.check_location_id = cl.id AND cl.is_deleted = '0'
        LEFT JOIN xp_cruise_check_in_rule cr ON r.cruise_check_in_rule_id = cr.id AND cr.is_deleted = '0'
        WHERE r.is_deleted = '0'
        <if test="query.fieldSituation != null">
            AND r.field_situation = #{query.fieldSituation}
        </if>
@@ -92,11 +92,11 @@
            r.scene_photo,
            r.scene_description
        FROM xp_cruise_check_in_record r
        LEFT JOIN xp_operations_user u ON r.operations_user_id = u.id AND u.del_flag = '0'
        LEFT JOIN xp_check_location cl ON r.check_location_id = cl.id AND cl.del_flag = '0'
        LEFT JOIN xp_cruise_check_in_rule cr ON r.cruise_check_in_rule_id = cr.id AND cr.del_flag = '0'
        LEFT JOIN xp_operations_user u ON r.operations_user_id = u.id AND u.is_deleted = '0'
        LEFT JOIN xp_check_location cl ON r.check_location_id = cl.id AND cl.is_deleted = '0'
        LEFT JOIN xp_cruise_check_in_rule cr ON r.cruise_check_in_rule_id = cr.id AND cr.is_deleted = '0'
        WHERE r.id = #{id}
          AND r.del_flag = '0'
          AND r.is_deleted = '0'
    </select>
    <select id="selectCruiseCheckInStatistics" resultMap="CruiseCheckInStatisticsMap">
@@ -107,11 +107,11 @@
        COUNT(CASE WHEN r.field_situation = 1 THEN 1 END) AS noTraffic,
        COUNT(CASE WHEN r.field_situation = 2 THEN 1 END) AS traffic
        FROM xp_cruise_check_in_record r
        LEFT JOIN xp_cruise_check_in_rule cr ON r.cruise_check_in_rule_id = cr.id AND cr.del_flag = '0'
        LEFT JOIN xp_operations_user u ON r.operations_user_id = u.id AND u.del_flag = '0'
        LEFT JOIN xp_cruise_check_in_rule cr ON r.cruise_check_in_rule_id = cr.id AND cr.is_deleted = '0'
        LEFT JOIN xp_operations_user u ON r.operations_user_id = u.id AND u.is_deleted = '0'
        LEFT JOIN xp_fleet_operations fo ON u.id = fo.operationsUserId
        LEFT JOIN xp_fleet f ON fo.fleetId = f.id
        WHERE r.del_flag = '0'
        WHERE r.is_deleted = '0'
        AND r.check_in_time IS NOT NULL
        <if test="query.ruleName != null and query.ruleName != ''">
            AND cr.name LIKE CONCAT('%', #{query.ruleName}, '%')
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpPointManagementController.java
@@ -3,7 +3,10 @@
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.xiaopeng.api.dto.map.XpPointExportExcelQuery;
import com.xiaopeng.api.dto.operation.PointAddDto;
import com.xiaopeng.api.dto.operation.PointUpdateDto;
@@ -72,12 +75,16 @@
    @ApiOperation(value = "获取所有运营中的区域", response = XpElectronicFenceArea.class)
    @PostMapping("/listElectronicFenceArea")
    public R<List<XpElectronicFenceArea>> listElectronicFenceArea(@RequestParam String cityCode) {
    public R<List<XpElectronicFenceArea>> listElectronicFenceArea(@RequestParam(required = false) String cityCode) {
        // 获取所有启用的电子围栏
        List<XpElectronicFence> electronicFences = xpElectronicFenceService.lambdaQuery()
                .eq(XpElectronicFence::getStatus, 2)
                .eq(XpElectronicFence::getCityCode, cityCode)
                .list();
        LambdaQueryWrapper<XpElectronicFence>  queryWrapper= new LambdaQueryWrapper<>();
        queryWrapper.eq(XpElectronicFence::getStatus, 2);
        if(StrUtil.isNotBlank(cityCode)){
            queryWrapper.eq(XpElectronicFence::getCityCode, cityCode);
        }
        List<XpElectronicFence> electronicFences = xpElectronicFenceService.list(queryWrapper);
        List<Long> electronicFenceIds = electronicFences.stream().map(XpElectronicFence::getId).collect(Collectors.toList());
        if (electronicFenceIds.isEmpty()) {
            return R.ok(new ArrayList<XpElectronicFenceArea>());
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpStationService.java
@@ -26,6 +26,8 @@
    PageInfo<XpStation> pageList(XpStationQuery query);
    boolean isPolygonInPolygon(String innerFencePoints, String outerFencePoints);
    void validate(XpStationVo dto);
    @Transactional
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpPointServiceImpl.java
@@ -57,6 +57,7 @@
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -104,6 +105,7 @@
    private XpElectronicFenceMapper xpElectronicFenceMapper;
    @Resource
    @Lazy
    private XpStationService xpStationService;
    @Resource
@@ -385,12 +387,12 @@
                        continue;
                    }
                    String downloadUrl ="";
                    try {
                        downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
                        log.info("downloadUrl:{}", downloadUrl);
                    } catch (UnsupportedEncodingException e) {
                        log.error("获取图片下载地址失败", e);
                    }
//                    try { todo 20260422 yyy暂时注释
//                        downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
//                        log.info("downloadUrl:{}", downloadUrl);
//                    } catch (UnsupportedEncodingException e) {
//                        log.error("获取图片下载地址失败", e);
//                    }
                    jsonObject.put("url", downloadUrl);
                }
                log.info("jsonArray:{}", jsonArray);
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpStationServiceImpl.java
@@ -26,6 +26,7 @@
import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
import org.springframework.data.mongodb.core.query.Criteria;
@@ -65,6 +66,7 @@
    private GDMapGeocodingUtil gdMapGeocodingUtil;
    @Autowired
    private XpRegionMapper xpRegionMapper;
    @Lazy
    @Resource
    private XpPointService xpPointService;
@@ -167,6 +169,7 @@
     * @param outerFencePoints 外部围栏点位字符串(参考围栏),格式为 "lng1_lat1,lng2_lat2,..."
     * @return 是否在内 true在内 false不在
     */
    @Override
    public boolean isPolygonInPolygon(String innerFencePoints, String outerFencePoints) {
        if (innerFencePoints == null || innerFencePoints.trim().isEmpty()
                || outerFencePoints == null || outerFencePoints.trim().isEmpty()) {
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpOpenCityController.java
@@ -47,6 +47,11 @@
        return R.ok(xpOpenCityService.citiesList());
    }
    @ApiOperation(value = "获取开通城市启用列表",tags = {"管理后台-开通城市-获取启用的数据"},response = XpOpenCityVo.class)
    @GetMapping("/api/v1/openCity/findLstEnable")
    public R<XpOpenCityVo> openCityFindList() {
        return R.ok(xpOpenCityService.citiesList());
    }
    /**
     * 获取开通城市列表(管理后台使用)
     * 用于路线规划配置的新增和编辑
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java
@@ -5,13 +5,11 @@
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.extension.service.impl.ServiceImpl;
import com.xiaopeng.api.dto.operation.PointMapQuery;
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.account.XpAppUserCollectAddr;
import com.xiaopeng.api.model.operation.*;
import com.xiaopeng.api.query.operation.PointListQuery;
import com.xiaopeng.api.query.operation.PointPageListListQuery;
@@ -35,7 +33,7 @@
import com.xiaopeng.operation.utils.TimeRangeChecker;
import com.xiaopeng.operation.utils.holiday.HolidayUtil;
import com.xiaopeng.operation.utils.map.FastDistanceCalculator;
import com.xiaopeng.operation.vo.NearestNextVo;
import com.xiaopeng.api.vo.operation.NearestNextVo;
import com.xiaopeng.operation.vo.NearestVo;
import com.xiaopeng.operation.vo.OrderDistanceVo;
import org.springframework.stereotype.Service;
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java
@@ -132,6 +132,7 @@
    /**
     * 5秒执行一次
     * 播单
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void taskOrder() {
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/NearestVo.java
@@ -1,5 +1,6 @@
package com.xiaopeng.operation.vo;
import com.xiaopeng.api.vo.operation.NearestNextVo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
@@ -16,10 +16,10 @@
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.operation.NearestNextVo;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.order.*;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.utils.WebUtils;
import com.xiaopeng.common.core.web.page.PageInfo;
@@ -341,6 +341,21 @@
    }
    /**
     * 获取用户快捷胶囊 历史 时段 终点高点
     */
    @ApiOperation(value = "获取首页快捷胶囊推荐站点", notes = "根据当前起点和用户近30天有效订单,按场景优先推荐目的地;无匹配时返回空数据", tags = {"小程序-首页快捷胶囊"}, response = XpPointInfoVo.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "startPointId", value = "当前首页起点站点ID", required = true, dataType = "Long", paramType = "query")
    })
    @GetMapping("/api/v1/mini-program/order/quick-capsule")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<NearestNextVo> quickCapsule(@RequestParam Long startPointId,HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        return R.ok(xpOrderService.quickCapsule(uid,startPointId));
    }
    /**
     * 获取订单详情
     */
    @PutMapping("/api/v1/mini-program/order/orderDetail/{orderId}")
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/mapper/XpOrderMapper.java
@@ -6,12 +6,12 @@
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.order.model.query.XpHistoryOrderListQuery;
import com.xiaopeng.order.model.vo.XpOrderHistoryListVO;
import com.xiaopeng.order.model.vo.XpOrderHistoryVO;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
/**
@@ -74,4 +74,7 @@
    List<XpOrder> listUserRecentValidOrders(@Param("uid") Long uid, @Param("startTime") LocalDateTime startTime);
    List<Long> timeSceneOrders(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDateTime endDate, @Param("startMoment") LocalTime startMoment, @Param("endMoment") LocalTime endMoment, @Param("userId") Long userId);
    List<Long> frequencyOrders(LocalDate startDate, LocalDateTime endDate, LocalTime startMoment, LocalTime endMoment, Long userId);
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java
@@ -8,6 +8,7 @@
import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.operation.NearestNextVo;
import com.xiaopeng.api.vo.order.FareBreakdownVo;
import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo;
import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo;
@@ -105,6 +106,8 @@
     * @return
     */
    XpPointInfoVo getUserQuickCapsule(String uid, Long startPointId);
    NearestNextVo quickCapsule(String uid, Long startPointId);
    /**
     * 获取历史下单成功起点10条数据列表
@@ -262,4 +265,5 @@
     * @return
     */
    OrderInfoVo getOrderInfo(Long orderId);
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -31,6 +31,7 @@
import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto;
import com.xiaopeng.api.feignClient.account.SysGroupMenuClient;
import com.xiaopeng.api.feignClient.account.UserResourcesClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCollectAddrClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.automaticPilot.VehicleBuriedPointClient;
@@ -51,6 +52,7 @@
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType;
import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderStatus;
import com.xiaopeng.api.vo.automaticPilot.protobuf.TaskActionType;
import com.xiaopeng.api.vo.operation.NearestNextVo;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.order.*;
import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo;
@@ -98,6 +100,8 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -1329,6 +1333,59 @@
        return null;
    }
    @Resource
    private XpAppUserCollectAddrClient xpAppUserCollectAddrClient;
    @Override
    public NearestNextVo quickCapsule(String uid, Long startPointId) {
        Long userId = Long.valueOf(uid);
        // - 新用户处理: 历史订单数 < 3单或无匹配数据时,隐藏该胶囊。
        Long validHistoryCount = this.baseMapper.countUserValidHistoryOrders(userId);
        if (validHistoryCount == null || validHistoryCount < 3) return null;
        LocalDateTime now = LocalDateTime.now();
        LocalTime startMoment = now.minusHours(1).toLocalTime();
        LocalTime endMoment = now.plusHours(1).toLocalTime();
        LocalDate startDate = now.minusMonths(1).toLocalDate();
        LocalDateTime endDate = now.plusMonths(1);
        // 时段强相关目的地(场景触发)当前时间点(当前时间 ± 1小时)内,过去30天内前往次数最多的目的地。
        List<Long> endPointId = this.baseMapper.timeSceneOrders(startDate, endDate, startMoment, endMoment, userId);
        // 判定条件: 若当前时段内无明显的规律性目的地(例如:用户在周六下午偶尔出门,且目的地不固定),则推荐用户过去30天内订单总量最高的前1名地址(需排除当前起点)。
        endPointId.addAll(this.baseMapper.frequencyOrders(startDate, endDate, startMoment, endMoment, userId));
        Integer minOrderDistance = getMinOrderDistanceSafely(uid, startPointId);
        if (minOrderDistance == null) return null;//获取用户最短可发单距离失败
        XpPoint start = getPointById(startPointId);
        GlobalCoordinates startCoordinates = new GlobalCoordinates(start.getPointLon(), start.getPointLat());
        List<Long> pointIdsByUserId = Optional.ofNullable(xpAppUserCollectAddrClient.getPointIdsByUserId(Long.valueOf(uid)).getData())
                .orElse(new ArrayList<>());
        for (Long pointId : endPointId) {
            XpPoint endPoint = getPointById(pointId);
            // 计算直线距离,如果endPoint到startPoint的距离大于minOrderDistance,则返回该点
            GlobalCoordinates endCoordinates = new GlobalCoordinates(endPoint.getPointLon(), endPoint.getPointLat());
            double distanceMeter = GeodesyUtil.getDistanceMeter(startCoordinates, endCoordinates, Ellipsoid.WGS84);
            if (distanceMeter > minOrderDistance) {
                NearestNextVo ret = new NearestNextVo();
                ret.setId(endPoint.getId());
                ret.setName(endPoint.getPointName());
                ret.setLatitude(endPoint.getPointLat());
                ret.setLongitude(endPoint.getPointLon());
                ret.setDistance(new BigDecimal(distanceMeter).setScale(2, RoundingMode.HALF_UP).doubleValue());
                ret.setAddress(endPoint.getPointAddress());
                ret.setTime(endPoint.getParkingTimeLimit());
                ret.setElectronicAreaId(endPoint.getElectronicAreaId());
                // 判断是否收藏
                if(pointIdsByUserId.contains(endPoint.getId())){
                    ret.setIsCollect(1);
                }
                return ret;
            }
        }
        return null;
    }
    private RecommendationCandidate buildSceneCandidate(List<XpOrder> recentOrders, LocalDateTime now, XpPoint startPoint, Integer minOrderDistance) {
        DaySceneType currentSceneType = resolveDaySceneType(now.toLocalDate());
        Set<Integer> targetHours = buildTargetHours(now.getHour());
xp-robotaxi-order-boot/src/main/resources/mapper/order/XpOrderMapper.xml
@@ -100,4 +100,28 @@
        ORDER BY create_time DESC
    </select>
    <select id="timeSceneOrders" resultType="java.lang.Long">
        SELECT
            end_point_id
        FROM xp_order
        WHERE app_user_id = #{userId}
          AND is_deleted = 0
          AND status IN (9, 10)
          AND DATE(create_time) BETWEEN #{startDate} AND #{endDate}
          AND TIME(create_time) BETWEEN #{startTime} AND #{endTime}
        GROUP BY end_point_id
        ORDER BY COUNT(*) DESC
    </select>
    <select id="frequencyOrders" resultType="java.lang.Long">
        SELECT
            end_point_id
        FROM xp_order
        WHERE app_user_id = #{userId}
          AND is_deleted = 0
          AND status IN (9, 10)
          AND DATE(create_time) BETWEEN #{startDate} AND #{endDate}
        GROUP BY end_point_id
        ORDER BY COUNT(*) DESC
    </select>
</mapper>
xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/webSocket/handler/PositionMsgHandler.java
@@ -3,6 +3,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaopeng.api.dto.account.XpOperationsUserPositionDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
@@ -11,6 +12,7 @@
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class PositionMsgHandler implements BusinessMsgHandler{
    @Override
@@ -49,6 +51,7 @@
            update.set("location", location);
            mongoTemplate.updateFirst(new Query(Criteria.where("id").is(dto.getId())), update, XpOperationsUserPositionDTO.class);
        }
        log.info("保存位置信息成功:id:{},longitude:{},latitude:{}", dto.getId(), dto.getLongitude(),dto.getLatitude());
    }
}
xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/webSocket/handler/TestMsgHandler.java
New file
@@ -0,0 +1,69 @@
package com.xiaopeng.pushMessage.webSocket.handler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaopeng.api.vo.TaskVO;
import com.xiaopeng.pushMessage.webSocket.service.WebSocketUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.HashMap;
@Component
@Slf4j
public class TestMsgHandler implements BusinessMsgHandler{
    @Override
    public String getMessageType() {
        return "test";
    }
    @Autowired
    private WebSocketUserService webSocketUserService;
    @Override
    public void handle(String uid, String msg) {
        TaskVO vo = new TaskVO();
        vo.setHandleUserId("1");
        vo.setId(1L);
        vo.setStatus(1);
        vo.setTaskCode("1");
        vo.setTaskTypeId("1");
        vo.setTaskTypeName("1");
        vo.setTaskUrgencyLevel(1);
        vo.setVehicleId(1L);
        vo.setVehicleLocation("1");
        vo.setPlateNumber("1");
        vo.setVehicleLat(BigDecimal.ZERO);
        vo.setVehicleLon(BigDecimal.ZERO);
        vo.setCanArriveRange(1D);
        vo.setEndTime(null);
        vo.setHandleUserId("1");
        vo.setVehicleLocation("1");
        vo.setPlateNumber("1");
        vo.setVehicleId(1L);
        vo.setCanArriveRange(1D);
        vo.setEndTime(null);
        vo.setHandleUserId("1");
        vo.setVehicleLocation("1");
        vo.setPlateNumber("1");
        vo.setVehicleId(1L);
        vo.setHandleUserId("1341243234");
        HashMap<String, Object> ret = new HashMap<>();
        ret.put("type", "task");
        ret.put("data", vo);
        try {
            msg = om.writeValueAsString(ret);
        } catch (JsonProcessingException e) {
            log.error("Failed to serialize message for uid: {}", uid, e);
            throw new RuntimeException("Message serialization failed", e);
        }
        webSocketUserService.sendMessageToUser(uid, msg);
    }
    @Autowired ObjectMapper om;
    @Autowired MongoTemplate mongoTemplate;
}
xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/webSocket/handler/WebSocketTextFrameHandler.java
@@ -165,23 +165,16 @@
        if (appUserId != null) {
            log.info("收到用户 {} 的业务消息: {}", appUserId, messageObj.toJSONString());
            businessMsgHandlers.get(messageObj.getString("type")).handle(appUserId, messageObj.getString("message"));
            //判断处理用户实时位置
            if ("location".equals(messageObj.getString("type"))) {
                log.info("收到用户 {} 的实时位置消息: {}", appUserId, messageObj.toJSONString());
                Double latitude = messageObj.getDouble("latitude");
                Double longitude = messageObj.getDouble("longitude");
                saveAppUserLocation(Long.parseLong(appUserId), latitude, longitude);
            }
            businessMsgHandlers.get(messageObj.getString("type")).handle(appUserId, messageObj.toJSONString());
            // 回复消息
            JSONObject response = new JSONObject();
            response.put("type", "message_response");
            response.put("appUserId", appUserId);
            response.put("originalMessage", messageObj);
            response.put("serverTime", LocalDateTime.now().toString());
            ctx.channel().writeAndFlush(new TextWebSocketFrame(response.toJSONString()));
//            JSONObject response = new JSONObject();
//            response.put("type", "message_response");
//            response.put("appUserId", appUserId);
//            response.put("originalMessage", messageObj);
//            response.put("serverTime", LocalDateTime.now().toString());
//
//            ctx.channel().writeAndFlush(new TextWebSocketFrame(response.toJSONString()));
        } else {
            log.warn("收到未认证连接的业务消息: {}", messageObj.toJSONString());
@@ -224,20 +217,4 @@
        ctx.channel().close();
    }
    private void saveAppUserLocation(Long appUserId, Double latitude, Double longitude) {
        AppUserPosition userPosition = mongoTemplate.findOne(Query.query(Criteria.where("appUserId").is(appUserId)), AppUserPosition.class);
        GeoJsonPoint point = new GeoJsonPoint(longitude, latitude);
        if(null != userPosition){
            mongoTemplate.updateFirst(Query.query(Criteria.where("appUserId").is(appUserId)),
                    Update.update("point", point).set("addTime", System.currentTimeMillis()), AppUserPosition.class);
        }else{
            userPosition = new AppUserPosition();
            userPosition.setAppUserId(appUserId);
            userPosition.setPoint(point);
            userPosition.setAddTime(System.currentTimeMillis());
            mongoTemplate.save(userPosition);
        }
    }
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -11,13 +11,13 @@
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.XpTask;
import com.xiaopeng.api.model.maintenance.XpTaskRule;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
@@ -25,6 +25,7 @@
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;
@@ -40,7 +41,7 @@
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.service.IXpFleetService;
import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService;
import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService;
@@ -57,6 +58,9 @@
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.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
@@ -64,6 +68,7 @@
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;
@@ -73,6 +78,7 @@
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
 * <p>
@@ -863,8 +869,8 @@
            @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);
    }
@@ -1156,4 +1162,38 @@
        VehicleDoorStatusVo vehicleDoorStatus = xpVehicleService.getVehicleDoorStatus(orderId);
        return R.ok(vehicleDoorStatus);
    }
    @Resource
    XpVehicleClient xpVehicleClient;
    /**
     * 周围车辆点位查询
     */
    @ApiOperation(value = "周围车辆点位查询", notes = "", tags = {"小程序-周围车辆点位查询"})
    @GetMapping("/api/v1/mini-program/vehicle/nearby")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<List<XpVehicleVO>> carAround(@RequestParam double lon,@RequestParam double lat,HttpServletRequest request) {
        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);
        List<XpVehicleVO> xpVehicleList = vehiclePositions.stream()
                .sorted(Comparator.comparingDouble(VehiclePositionVo::getDistance))
                .map(vp -> {
                    XpVehicle xpVehicle = xpVehicleClient.findByVehicleVin(vp.getVin()).getData();
                    XpVehicleVO vo = new XpVehicleVO();
                    BeanUtils.copyProperties(xpVehicle, vo);
                    vo.setDirection(vp.getCourse());
                    return vo;
                })
                .filter(v -> v.getState() == 0)
                .limit(5)
                .collect(Collectors.toList());
        return R.ok(xpVehicleList);
    }
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/mapper/XpVehicleMapper.java
@@ -8,7 +8,7 @@
import com.xiaopeng.vehicleConvoy.model.query.VehicleExportQuery;
import com.xiaopeng.vehicleConvoy.model.query.VehicleMapQuery;
import com.xiaopeng.vehicleConvoy.model.query.VehiclePageQuery;
import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO;
import com.xiaopeng.api.vo.vehicleConvoy.XpVehicleVO;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDate;
@@ -65,6 +65,8 @@
     */
    List<XpVehicleVO> pageList(@Param("pageInfo") PageInfo<XpVehicleVO> pageInfo, @Param("query") VehicleMapQuery query);
    List<XpVehicleVO> findList(@Param("query") VehicleMapQuery query);
    /**
     * 在库车辆管理分页查询
     *
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/model/query/VehicleMapQuery.java
@@ -14,6 +14,10 @@
    private String plateNumber;
    @ApiModelProperty(value = "运营状态 1运营中 2维修中 3已收车 4车辆异常")
    private String status;
    @ApiModelProperty(value = "运营状态 1运营中 2维修中 3已收车 4车辆异常")
    private Integer operatingStatus;
    @ApiModelProperty(value = "车辆接单状态 1接单中 0空闲")
    private Integer state;
    @ApiModelProperty(value = "围栏id")
    private String electronicId;
@@ -25,4 +29,11 @@
    private Long operationsUserId;
    @ApiModelProperty(value = "车辆id集合 前端忽略")
    private List<Long> vehicleIds;
    @ApiModelProperty(value = "车辆类型 1=在库 2=运营")
    private Integer vehicleType;
    @ApiModelProperty(value = "车队名称")
    private String fleetName;
}
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java
@@ -1,6 +1,5 @@
package com.xiaopeng.vehicleConvoy.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiaopeng.api.dto.vehicleConvoy.ServiceVehicleListDto;
import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto;
@@ -11,10 +10,7 @@
import com.xiaopeng.vehicleConvoy.model.dto.*;
import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel;
import com.xiaopeng.vehicleConvoy.model.query.*;
import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import com.xiaopeng.api.vo.vehicleConvoy.XpVehicleVO;
import java.util.List;
@@ -40,7 +36,8 @@
     *
     * @return 车辆列表
     */
    List<XpVehicle> listAvailableVehicles(Long orderId, Integer orderType);
    List<XpVehicleVO> listAvailableVehicles(Long orderId, Integer orderType, String plateNumber, String fleetName);
    /**
     * 查询车辆列表接口-地图
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -53,7 +53,7 @@
import com.xiaopeng.vehicleConvoy.model.dto.*;
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.service.AsyncVehicleStateService;
import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService;
import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService;
@@ -82,7 +82,6 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -169,7 +168,7 @@
     * @return
     */
    @Override
    public List<XpVehicle> listAvailableVehicles(Long orderId, Integer orderType) {
    public List<XpVehicleVO> listAvailableVehicles(Long orderId, Integer orderType, String plateNumber, String fleetName) {
        // 1. 通过订单ID查询订单信息,获取区域ID
        Long areaId = null;
@@ -212,16 +211,15 @@
        }
        // 3. 根据围栏ID查询车辆列表 (operatingStatus=1 且 state=0)
        LambdaQueryWrapper<XpVehicle> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(XpVehicle::getElectronicId, electronicId)
                .eq(XpVehicle::getOperatingStatus, 1)
                .eq(XpVehicle::getVehicleType, 2)
                .eq(XpVehicle::getState, 0);
        VehicleMapQuery query = new VehicleMapQuery();
        query.setState(0);
        query.setVehicleType(2);
        query.setOperatingStatus(1);
        query.setElectronicId(electronicId.toString());
        query.setFleetName(fleetName);
        query.setPlateNumber(plateNumber);
        // 排序:按电量降序、入库时间降序
        wrapper.orderByDesc(XpVehicle::getCurrentElectricity)
                .orderByDesc(XpVehicle::getWarehousingTime);
        List<XpVehicle> list = this.list(wrapper);
        List<XpVehicleVO> list = baseMapper.findList(query);
        //获取车的位置 和订单的位置 并计算 距离 和 时间
        if(!list.isEmpty()){
            for (XpVehicle xpVehicle : list) {
xp-robotaxi-vehicle-convoy-boot/src/main/resources/mapper/vehicleConvoy/XpVehicleMapper.xml
@@ -65,7 +65,7 @@
        GROUP BY DATE(create_time)
        ORDER BY date ASC
    </select>
    <select id="pageList" resultType="com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO">
    <select id="pageList" resultType="com.xiaopeng.api.vo.vehicleConvoy.XpVehicleVO">
        SELECT <include refid="Base_Column_List"></include>
        FROM xp_vehicle
        <where>
@@ -94,6 +94,58 @@
            AND vehicle_type = 2
        </where>
        ORDER BY create_time DESC
    </select>
    <select id="findList" resultType="com.xiaopeng.api.vo.vehicleConvoy.XpVehicleVO">
        SELECT a.*
        FROM xp_vehicle as a
        <where> a.is_deleted = 0
            <if test="query.vehicleType != null and query.vehicleType != ''">
                AND a.vehicle_type = #{query.vehicleType}
            </if>
            <if test="query.plateNumber != null and query.plateNumber != ''">
                AND a.plate_number LIKE CONCAT('%', #{query.plateNumber}, '%')
            </if>
            <!-- 运营状态 1运营中 2维修中 3已收车 4车辆异常 -->
            <if test="query.operatingStatus != null and query.operatingStatus != ''">
                AND a.operating_status = #{query.operatingStatus}
            </if>
            <!-- 车辆接单状态 1接单中 0空闲 -->
            <if test="query.state != null and query.state != ''">
                AND a.state = #{query.state}
            </if>
            <if test="query.statusList != null and query.statusList.size()>0">
                AND a.operating_status in
                <foreach item="item" collection="query.statusList" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </if>
            <if test="query.electronicId != null and query.electronicId != ''">
                    AND a.electronic_id #{query.electronicId}
                </if>
            <if test="query.electronicIdList != null and query.electronicIdList.size()>0">
                AND a.electronic_id in
                <foreach item="item" collection="query.electronicIdList" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </if>
            <if test="query.vehicleIds != null and query.vehicleIds.size()>0">
                AND a.id in
                <foreach item="item" collection="query.vehicleIds" separator="," open="(" close=")">
                    #{item}
                </foreach>
            </if>
            <if test="query.fleetName != null and query.fleetName != ''">
                AND EXISTS (
                    SELECT 1 FROM xp_fleet_vehicle xfv
                    LEFT JOIN xp_fleet xf ON xfv.fleet_id = xf.id
                    WHERE xfv.vehicle_id = a.id
                    AND xf.fleet_name LIKE CONCAT('%', #{query.fleetName}, '%')
                )
            </if>
        </where>
        ORDER BY a.current_electricity DESC,a.warehousing_time desc
    </select>
    <!-- 在库车辆管理分页查询条件 -->
@@ -139,7 +191,7 @@
        </where>
        ORDER BY create_time DESC
    </select>
    <select id="getVehiclePageList" resultType="com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO">
    <select id="getVehiclePageList" resultType="com.xiaopeng.api.vo.vehicleConvoy.XpVehicleVO">
        select xv.id,
        xv.vehicle_code,
        xv.vehicle_vin,