xuhy
2026-02-28 5a719e0ce31feccb4da0073905d5f64e3d785def
Merge remote-tracking branch 'origin/master'
9个文件已添加
40个文件已修改
1132 ■■■■■ 已修改文件
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/SysUserController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/pushMessage/AliPushMessageDTO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/XpElectronicClientFallbackFactory.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/XpElectronicClient.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpOperationsUserNotification.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpTask.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpWorkOrder.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpWorkOrderLog.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/order/XpPricingCardVo.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/base/AbstractJob.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/base/QuartzManager.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/base/TimeJobType.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/exceptions/TimeException.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/jobs/AddCruiseMissionJob.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/jobs/EndTripJob.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/jobs/OrderCancelJob.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/utils/SpringContextsUtil.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/service/impl/XpPricingServiceImpl.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpTaskManagementController.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpWorkOrderController.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/InsuranceInspectionScheduleTask.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/RoutinePreparationScheduleTask.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleCleanScheduleTask.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleCollectionScheduleTask.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleInspectionScheduleTask.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleMaintenanceScheduleTask.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpSchedulingDetailServiceImpl.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpWorkOrderServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpElectronicFenceManagementController.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpPointManagementController.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpElectronicFenceAreaController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpElectronicFenceController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpPointManagementController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpWhitelistController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/exportExcle/XpWhitelistExportExcel.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpWhitelistServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/resources/mapper/operation/XpWhitelistMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/AbstractJob.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/TimeJobType.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/AddCruiseMissionJob.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java 248 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages.properties 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages_zh_CN.properties 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/SysUserController.java
@@ -74,6 +74,15 @@
        PageInfo<SysUser> page = userService.getList(pageInfo, sysUserListQuery);
        return AjaxResult.success(page);
    }
    /**
     * 获取用户不分页列表
     */
    @GetMapping("/api/v1/sys-user/listAll")
    @ApiOperation(value = "账号管理不分页列表", tags = {"管理后台-账号管理"})
    public R<List<SysUser>> listAll() {
        List<SysUser> listAll = userService.list();
        return R.ok(listAll);
    }
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/pushMessage/AliPushMessageDTO.java
@@ -2,15 +2,15 @@
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Builder
@Accessors(chain = true)
@ApiModel(value = "ali推送消息AliPushMessageDTO")
@AllArgsConstructor
@NoArgsConstructor
public class AliPushMessageDTO implements Serializable {
    @ApiModelProperty(value = "设备类型")
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/XpElectronicClientFallbackFactory.java
@@ -5,6 +5,7 @@
import com.xiaopeng.api.dto.operation.ElectronicFenceUpdateDto;
import com.xiaopeng.api.feignClient.operation.XpElectronicClient;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpElectronicFenceArea;
import com.xiaopeng.api.query.operation.ElectronicPageListQuery;
import com.xiaopeng.api.vo.operation.ElectronicFenceDetailVo;
import com.xiaopeng.common.core.domain.R;
@@ -67,6 +68,12 @@
                log.error("根据ID列表批量查询电子围栏失败:{}", cause.getMessage());
                return R.fail("根据ID列表批量查询电子围栏失败");
            }
            @Override
            public R<XpElectronicFenceArea> queryElectronicFenceAreaById(Long id) {
                log.error("通过区域ID查询围栏失败:{}", cause.getMessage());
                return R.fail("通过区域ID查询围栏失败");
            }
        };
    }
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/XpElectronicClient.java
@@ -5,6 +5,7 @@
import com.xiaopeng.api.dto.operation.ElectronicFenceUpdateDto;
import com.xiaopeng.api.factory.operation.XpPointClientFallbackFactory;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpElectronicFenceArea;
import com.xiaopeng.api.query.operation.ElectronicPageListQuery;
import com.xiaopeng.api.vo.operation.ElectronicFenceDetailVo;
import com.xiaopeng.common.core.domain.R;
@@ -57,4 +58,13 @@
     */
    @PostMapping("/api/v1/electronicFence/listByIds")
    R<List<XpElectronicFence>> listByIds(@RequestBody Collection<Long> electronicIdSet);
    /**
     * 根据区域ID查询电子围栏区域信息
     *
     * @param id 区域ID
     * @return 区域信息
     */
    @PostMapping("/inner/v1/xp-electronic-fence-area/queryById")
    R<XpElectronicFenceArea> queryElectronicFenceAreaById(@RequestParam("id") Long id);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpOperationsUserNotification.java
@@ -50,4 +50,7 @@
    @ApiModelProperty(value = "是否已读 0-未读 1-已读")
    private Integer readStatus;
    @ApiModelProperty(value = "阿里云推送body内容")
    private String notificationExt;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpTask.java
@@ -85,6 +85,6 @@
    @ApiModelProperty(value = "状态 0=待到达 1=待处理 2=已完成 3=已取消")
    private Integer status;
    private String belongUserIds;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpWorkOrder.java
@@ -63,6 +63,7 @@
    @ApiModelProperty(value = "处理状态 1待处理 2处理中 3已处理")
    private Integer handleStatus;
    @ApiModelProperty(value = "如果状态为待处理或者处理中 是否可以处理 0否 1是")
    @TableField(exist = false)
    private Integer isHandle;
    @ApiModelProperty(value = "处理人id")
    private Long handleUserId;
@@ -72,6 +73,9 @@
    @ApiModelProperty(value = "处理日志")
    @TableField(exist = false)
    private List<XpWorkOrderLog> workOrderLogs;
    @ApiModelProperty(value = "创建人id")
    private Long createById;
    @ApiModelProperty(value = "创建人头像")
    @TableField(exist = false)
    private String createByAvatar;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpWorkOrderLog.java
@@ -46,6 +46,10 @@
    @ApiModelProperty(value = "所属处理人名称")
    @TableField(exist = false)
    private String handleUserName;
    @ApiModelProperty(value = "所属处理人touxiang")
    @TableField(exist = false)
    private String handleUserAvatar;
    @ApiModelProperty(value = "操作类型 1移交 2办结")
    private Integer handleType;
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/order/XpPricingCardVo.java
@@ -44,4 +44,9 @@
    @ApiModelProperty(value = "优惠券")
    private String coupon;
    @ApiModelProperty("系统优惠金额")
    private Double systemDiscount;
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/base/AbstractJob.java
New file
@@ -0,0 +1,35 @@
package com.xiaopeng.automaticPilot.job.base;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.order.job.utils.SpringContextsUtil;
import com.xiaopeng.order.service.IXpCruiseOrderService;
import com.xiaopeng.order.service.IXpOrderService;
import com.xiaopeng.order.service.XpOrderTimeoutLogService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractJob implements Job {
    protected Logger logger = LoggerFactory.getLogger(getClass());
    @Override
    public abstract void execute(JobExecutionContext context) throws JobExecutionException;
    protected IXpOrderService xpOrderService;
    protected XpPushMessageClient xpPushMessageClient;
    protected XpOrderTimeoutLogService xpOrderTimeoutLogService;
    protected IXpCruiseOrderService xpCruiseOrderService;
    protected OrderMissionClient orderMissionClient;
    protected XpVehicleClient xpVehicleClient;
    public AbstractJob(){
        this.xpOrderService = SpringContextsUtil.getBean(IXpOrderService.class);
        this.xpPushMessageClient = SpringContextsUtil.getBean(XpPushMessageClient.class);
        this.xpOrderTimeoutLogService = SpringContextsUtil.getBean(XpOrderTimeoutLogService.class);
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/base/QuartzManager.java
New file
@@ -0,0 +1,129 @@
package com.xiaopeng.automaticPilot.job.base;
import com.xiaopeng.order.job.base.TimeJobType;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.Date;
import java.util.Map;
public class QuartzManager {
    private static SchedulerFactory factory = new StdSchedulerFactory();
    private static final String TRIGGER_NAME_PREFIX = "TRIGGER_PREFIX_";
    private static final String JOB_NAME_PREFIX = "JOB_PREFIX_";
    /**
     * 添加定时任务:具体某个时间点执行一次的任务,如:在某个2015-06-01 12:00发送一条消息
     *
     * @param jobName
     *            具体的任务名+ID标识唯一
     * @param jobType
     * @param date
     * @param jp
     */
    public synchronized static void addJob(Class<? extends Job> jobClass, String jobName, TimeJobType jobType, Date date,
                                           Map<String,  ? extends Object> jp) {
        //logger.debug("ADD JOB {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date);
        try {
            Scheduler sched = factory.getScheduler();
            JobDetail job = JobBuilder.newJob(jobClass).withIdentity(JOB_NAME_PREFIX + jobName, jobType.getType())
                    .setJobData(new JobDataMap(jp)).build();
            SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                    .withIdentity(TRIGGER_NAME_PREFIX + jobName, jobType.getType()).startAt(date).build();
            removeJob(jobName, jobType);
            sched.scheduleJob(job, trigger);
            if (!sched.isShutdown()) {
                sched.start();
            }
        } catch (Exception e) {
            //logger.error("ADD JOB exception {},jobName={},jobTyep={},jobDate={},",jobClass.getName(),jobName,jobType,date);
        }
    }
       /**
        * 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
        * @param jobName
        * @param time
        */
        public synchronized static void modifyJobTime(String jobName,TimeJobType jobType, Date time) {
             //logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time);
            try {
                JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType());
                TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType());
                Scheduler sched = factory.getScheduler();
                SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(key);
                if(trigger == null) {
                    return;
                }
                Date oldTime = trigger.getStartTime();
                if (oldTime.getTime() != time.getTime()) {
                    JobDetail jobDetail = sched.getJobDetail(jobKey);
                    Class<? extends Job> objJobClass = jobDetail.getJobClass();
                    removeJob(jobName,jobType);
                    Map<String, Object> jp = jobDetail.getJobDataMap();
                    addJob(objJobClass, jobName, jobType, time, jp);
                }
            } catch (Exception e) {
               // logger.error("Update JOB exception,jobName={},jobTyep={},jobDate={}," ,jobName,jobType,time);
            }
        }
    /**
     * 移除一个任务
     *
     * @param jobName
     */
    public synchronized static void removeJob(String jobName, TimeJobType jobType) {
        try {
            JobKey jobKey = new JobKey(JOB_NAME_PREFIX + jobName, jobType.getType());
            TriggerKey key = new TriggerKey(TRIGGER_NAME_PREFIX + jobName, jobType.getType());
            Scheduler sched = factory.getScheduler();
            JobDetail detail = sched.getJobDetail(jobKey);
            if (detail != null) {
                sched.pauseJob(jobKey);
                sched.pauseTrigger(key);// 停止触发器
                sched.unscheduleJob(key);// 移除触发器
                sched.deleteJob(jobKey);// 删除任务
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 启动所有定时任务
     */
    public synchronized static void startJobs() {
        try {
            Scheduler sched = factory.getScheduler();
            sched.start();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 关闭所有定时任务
     */
    public synchronized static void shutdownJobs() {
        try {
            Scheduler sched = factory.getScheduler();
            if (!sched.isShutdown()) {
                sched.shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/base/TimeJobType.java
New file
@@ -0,0 +1,30 @@
package com.xiaopeng.automaticPilot.job.base;
/**
 * @Description 按时间点发布的任务类型
 * @date 2025年2月17日 下午7:22:28
 */
public enum TimeJobType {
    ORDER_CANCEL("order_cancel","订单取消"),
    ADD_CRUISE_MISSION("add_cruise_mission","添加巡游任务"),
    END_TRIP("end_trip","自动结束行程");
    private String type;
    private String desc;
    private TimeJobType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/exceptions/TimeException.java
New file
@@ -0,0 +1,37 @@
package com.xiaopeng.automaticPilot.job.exceptions;
/**
 * @文件说明:定时器任务执行异常
 * @版权所有:成都喜来达
 * @项目名称: fengsheng
 * @创建者: Leeyns
 * @创建日期: 2016年5月18日
 * @最近修改者:Leeyns
 * @最近修改日期:2016年5月18日
 */
public class TimeException extends Exception {
    /**
     *  TODO
     */
    private static final long serialVersionUID = 5703430073981692250L;
    private String message;
    public TimeException() {
        super();
    }
    public TimeException(String message) {
        super(message);
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/jobs/AddCruiseMissionJob.java
New file
@@ -0,0 +1,40 @@
package com.xiaopeng.automaticPilot.job.jobs;
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.model.order.XpCruiseOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.order.job.base.AbstractJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
 * 推送定时任务
 * @author Administrator
 *
 */
@Slf4j
public class AddCruiseMissionJob extends AbstractJob {
    public static final String name = "addCruiseMission_";
    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        JobDataMap maps = context.getMergedJobDataMap();
        Long orderId = maps.getLong("id");
        try {
            log.info("开始执行添加任务");
            XpCruiseOrder xpCruiseOrder = xpCruiseOrderService.getById(orderId);
            R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(xpCruiseOrder.getVehicleId());
            if(xpVehicleR.getData().getState()==0){
                orderMissionClient.pushOrder(new PushOrderDto(xpCruiseOrder.getVehicleVin(),xpCruiseOrder.getId(),null));
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/jobs/EndTripJob.java
New file
@@ -0,0 +1,41 @@
package com.xiaopeng.automaticPilot.job.jobs;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.order.XpOrderTimeoutLog;
import com.xiaopeng.order.job.base.AbstractJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
 * 推送定时任务
 * @author Administrator
 *
 */
@Slf4j
public class EndTripJob extends AbstractJob {
    public static final String name = "endTrip_";
    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        JobDataMap maps = context.getMergedJobDataMap();
        Long orderId = maps.getLong("id");
        try {
            log.info("开始执行自动结束行程任务");
            XpOrder xpOrder = xpOrderService.getById(orderId);
            xpOrderService.endTrip(xpOrder.getId(), String.valueOf(xpOrder.getAppUserId()));
            log.info("结束执行自动结束行程任务");
            // 添加超时记录
            XpOrderTimeoutLog xpOrderTimeoutLog = new XpOrderTimeoutLog();
            xpOrderTimeoutLog.setOrderId(xpOrder.getId());
            xpOrderTimeoutLog.setUserId(xpOrder.getAppUserId());
            xpOrderTimeoutLogService.save(xpOrderTimeoutLog);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/jobs/OrderCancelJob.java
New file
@@ -0,0 +1,40 @@
package com.xiaopeng.automaticPilot.job.jobs;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.order.job.base.AbstractJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Objects;
/**
 * 直播推送定时任务
 * @author Administrator
 *
 */
@Slf4j
public class OrderCancelJob extends AbstractJob {
    public static final String name = "orderCancel_";
    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        JobDataMap maps = context.getMergedJobDataMap();
        Long orderId = maps.getLong("id");
        try {
            log.info("开始执行订单取消任务");
            XpOrder xpOrder = xpOrderService.getById(orderId);
            if(Objects.nonNull(xpOrder)){
                log.info("订单取消开始");
                xpOrderService.cancelOrder(String.valueOf(xpOrder.getId()));
                log.info("订单取消状态修改完成");
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/job/utils/SpringContextsUtil.java
New file
@@ -0,0 +1,37 @@
package com.xiaopeng.automaticPilot.job.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextsUtil implements ApplicationContextAware{
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringContextsUtil.applicationContext == null) {
            SpringContextsUtil.applicationContext = applicationContext;
        }
    }
    // 获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    // 通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }
    // 通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }
    // 通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        System.out.println(getApplicationContext().getBean(name, clazz));
        return getApplicationContext().getBean(name, clazz);
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -27,6 +27,14 @@
import com.xiaopeng.api.vo.OrderType;
import com.xiaopeng.api.vo.SystemEventType;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.ActionType;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperationType;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.PointType;
import com.xiaopeng.api.vo.automaticPilot.proto.up.navigationDeviationEvent.NavigationDeviationEvent;
import com.xiaopeng.api.vo.automaticPilot.proto.up.navigationDeviationEvent.NavigationDeviationMessage;
import com.xiaopeng.api.vo.automaticPilot.proto.up.orderStateUpdateEvent.OrderStatusInfoEvent;
import com.xiaopeng.api.vo.automaticPilot.proto.up.systemStatusXpu.*;
import com.xiaopeng.api.vo.automaticPilot.proto.up.xpuNavigationRequest.NavigationRequest;
import com.xiaopeng.api.vo.automaticPilot.protobuf.*;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo;
@@ -846,6 +854,15 @@
                            lastXpCruiseOrder.setStatus(1);
                            xpCruiseOrderClient.addCruiseOrder(lastXpCruiseOrder);
                            // 获取点位id
                            Long endPointId = xpCruiseOrder.getEndPointId();
                            // 获取点位信息 获取点位是否需要停车
//                            xpCruisePlanClient.getPlanPointInfo(endPointId);
                            com.xiaopeng.api.vo.automaticPilot.protobuf.RtTask.Builder taskBuilder = com.xiaopeng.api.vo.automaticPilot.protobuf.RtTask.newBuilder();
                            taskBuilder.setOrderId(lastXpCruiseOrder.getId());
                            taskBuilder.setTaskId("MISSION_"+ IdUtil.fastUUID());
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/service/impl/XpPricingServiceImpl.java
@@ -287,7 +287,13 @@
        }
        UserCouponVo userCouponVo = couponResult.getData();
        if (userCouponVo != null) {
            Double money = userCouponVo.getMoney();
            xpPricingCardVo.setCoupon(String.valueOf(userCouponVo.getMoney()));
            if(xpPricingCardVo.getTotalPrice()> money){
                xpPricingCardVo.setSystemDiscount(xpPricingCardVo.getTotalPrice() - money);
            }
        }
        // 8. 构建响应对象
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpTaskManagementController.java
@@ -156,7 +156,7 @@
        return xpTaskService.taskDetail(id);
    }
    @ApiOperation(value = "查询车辆不分页列表")
    @PostMapping(" /listVehicle")
    @PostMapping("/listVehicle")
    public R<List<XpVehicle>> listVehicle() {
        List<XpVehicle> vehicles = xpVehicleClient.listVehicle().getData();
        if (vehicles == null){
@@ -177,7 +177,7 @@
    @ApiOperation(value = "事故类型列表", response = XpErrorType.class, tags = "管理后台-车辆管理-运营车辆管理")
    @GetMapping(" /errorTypeTreeList")
    @GetMapping("/errorTypeTreeList")
    public R<List<XpErrorType>> errorTypeTreeList() {
        return xpErrorTypeService.errorTypeList();
    }
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpWorkOrderController.java
@@ -55,6 +55,7 @@
    @ApiOperation(value = "创建工单")
    @PostMapping("/saveWorkOrder")
    public R saveWordOrder(@RequestBody XpWorkOrder workOrder) {
        workOrder.setCreateById(tokenService.getLoginUser().getSysUser().getId());
        workOrderService.save(workOrder);
        return R.ok();
    }
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/InsuranceInspectionScheduleTask.java
@@ -353,7 +353,7 @@
            task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE);
            // 设置任务接收人(配置角色下的所有运维人员都可以看到)
            task.setBelongUserIds(belongUserIds);
            task.setHandleUserId(belongUserIds);
            // 设置创建信息
            task.setReportTime(LocalDateTime.now());
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/RoutinePreparationScheduleTask.java
@@ -373,7 +373,7 @@
            task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE);
            // 设置任务接收人(配置角色下的所有运维人员都可以看到)
            task.setBelongUserIds(belongUserIds);
            task.setHandleUserId(belongUserIds);
            // 设置创建信息
            task.setReportTime(LocalDateTime.now());
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleCleanScheduleTask.java
@@ -373,7 +373,7 @@
            task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE);
            // 设置任务接收人(配置角色下的所有运维人员都可以看到)
            task.setBelongUserIds(belongUserIds);
            task.setHandleUserId(belongUserIds);
            // 设置创建信息
            task.setReportTime(LocalDateTime.now());
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleCollectionScheduleTask.java
@@ -1,14 +1,24 @@
package com.xiaopeng.maintenance.schedule;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.operation.XpCruisePlanClient;
import com.xiaopeng.api.feignClient.order.XpCruiseOrderClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.maintenance.XpTaskRule;
import com.xiaopeng.api.model.order.XpCruiseOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@@ -42,6 +52,18 @@
    @Autowired
    private XpVehicleClient xpVehicleClient;
    @Autowired
    private XpCruiseOrderClient xpCruiseOrderClient;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private OrderMissionClient orderMissionClient;
    @Autowired
    private XpCruisePlanClient xpCruisePlanClient;
    /**
     * 每分钟检查一次是否需要执行收车任务
@@ -162,6 +184,7 @@
                return result.getData().stream()
                        .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2)
                        .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1)
                        .filter(v -> v.getState() != null && v.getState() == 0)
                        .collect(Collectors.toList());
            }
        } catch (Exception e) {
@@ -179,10 +202,37 @@
     * 2. 更新车辆状态为"已收车"
     * </p>
     *
     * @param vehicle 车辆信息
     * @param xpVehicle 车辆信息
     */
    private void sendCollectionCommand(XpVehicle vehicle) {
        // TODO: 具体发送收车指令的实现
        log.info("向车辆[{}]发送收车指令", vehicle.getPlateNumber());
    private void sendCollectionCommand(XpVehicle xpVehicle) {
        // 收车 关闭当前巡游单子 生成新的返程单子  找到收车站点
        R<String> r = xpCruiseOrderClient.updateCruiseOrder(xpVehicle.getVehicleVin());
        // mongodb 获取当前最新经纬度位置
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
        XpCruiseOrder xpCruiseOrder = new XpCruiseOrder();
        if(vehiclePosition!=null){
            double x = vehiclePosition.getPoint().getX();
            double y = vehiclePosition.getPoint().getY();
            xpCruiseOrder.setStartLon(x);
            xpCruiseOrder.setStartLat(y);
        }
        xpCruiseOrder.setId("XU"+ IdUtil.fastUUID());
        xpCruiseOrder.setVehicleId(xpVehicle.getId());
        xpCruiseOrder.setFleetId(xpVehicle.getFleetId());
        xpCruiseOrder.setOrderType(2);
        xpCruiseOrder.setStatus(1);
        xpCruiseOrder.setOrderReverse(1);
        xpCruiseOrder.setLastOrderId(r.getData());
        // 找到收车站点
        R<XpCruiseOrder> returnCruisePoint = xpCruisePlanClient.findReturnCruisePoint(xpCruiseOrder);
        if(returnCruisePoint!=null){
            xpCruiseOrderClient.addCruiseOrder(returnCruisePoint.getData());
            // 下发命令
            orderMissionClient.pushOrder(new PushOrderDto( xpCruiseOrder.getVehicleVin(),xpCruiseOrder.getId(),null));
        }
        log.info("向车辆[{}]发送收车指令", xpVehicle.getPlateNumber());
    }
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleInspectionScheduleTask.java
@@ -333,7 +333,7 @@
            task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE);
            // 设置任务接收人(配置角色下的所有运维人员都可以看到)
            task.setBelongUserIds(belongUserIds);
            task.setHandleUserId(belongUserIds);
            // 设置创建信息
            task.setReportTime(LocalDateTime.now());
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleMaintenanceScheduleTask.java
@@ -359,7 +359,7 @@
            task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE);
            // 设置任务接收人(配置角色下的所有运维人员都可以看到)
            task.setBelongUserIds(belongUserIds);
            task.setHandleUserId(belongUserIds);
            // 设置创建信息
            task.setReportTime(LocalDateTime.now());
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpSchedulingDetailServiceImpl.java
@@ -1,16 +1,24 @@
package com.xiaopeng.maintenance.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.api.dto.pushMessage.AliPushMessageDTO;
import com.xiaopeng.api.feignClient.account.XpOperationUserClient;
import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient;
import com.xiaopeng.api.feignClient.maintenance.XpCheckLocationClient;
import com.xiaopeng.api.feignClient.pushMessage.XpAliPushMessageClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetOperationsClient;
import com.xiaopeng.api.model.account.XpOperationsUser;import com.xiaopeng.api.model.maintenance.*;
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.vehicleConvoy.XpFleet;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.NotificationTypeEnum;
import com.xiaopeng.common.core.utils.poi.ExcelUtil;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.maintenance.dto.ExportSchedulingDetailDto;
@@ -36,6 +44,9 @@
import java.time.format.TextStyle;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * <p>
@@ -64,6 +75,10 @@
    private XpFleetOperationsClient xpFleetOperationsClient;
    @Resource
    private XpOperationUserClient xpOperationUserClient;
    @Resource
    private XpAliPushMessageClient xpAliPushMessageClient;
    @Resource
    private XpOperationUserNotificationClient xpOperationUserNotificationClient;
    @Override
    public ShiftAttendanceVO shiftAttendance(ShiftAttendanceDTO dto) {
@@ -395,6 +410,10 @@
        //构建排班明细数据
        List<SaveSchedulingDetailVo> datas = vo.getDatas();
        List<XpSchedulingDetail> schedulingDetails = new ArrayList<>();
        //存放推送消息
        List<AliPushMessageDTO> pushMessage = new ArrayList<>();
        //存放通知数据
        List<XpOperationsUserNotification> notifications = new ArrayList<>();
        for (SaveSchedulingDetailVo data : datas) {
            Long fleetId = data.getFleetId();
            List<SaveSchedulingDetailDay> days = data.getDays();
@@ -428,7 +447,12 @@
                            for (XpOperationsUser xpOperationsUser : data1) {
                                String nickName = xpOperationsUser.getNickName();
                                String message = nickName + "请注意," + month + "你的排班由" + xpShift1.getShiftName() + "变更为了" + xpShift2.getShiftName() + "。详情请联系平台管理员。";
                                //构建消息推送对象
                                AliPushMessageDTO aliPushMessageDTO = buildPushMessage(message, xpOperationsUser);
                                pushMessage.add(aliPushMessageDTO);
                                //构建消息存储
                                XpOperationsUserNotification operationsUserNotification = buildXpOperationsUserNotification(message, aliPushMessageDTO.getBody(), xpOperationsUser);
                                notifications.add(operationsUserNotification);
                            }
                        }
                    }
@@ -448,11 +472,74 @@
        if(schedulingDetails.isEmpty()){
            this.saveOrUpdateBatch(schedulingDetails);
        }
        //异步处理消息通知数据
        pushMessage(pushMessage, notifications);
        return R.ok();
    }
    /**
     * 构建推送消息对象
     * @param message
     * @param xpOperationsUser
     * @return
     */
    private AliPushMessageDTO buildPushMessage(String message, XpOperationsUser xpOperationsUser){
        JSONObject body = new JSONObject();
        body.put("content", message);
        body.put("strategy", 4);
        body.put("type", 0);
        body.put("id", 0);
        AliPushMessageDTO aliPushMessageDTO = new AliPushMessageDTO();
        aliPushMessageDTO.setDeviceType(xpOperationsUser.getDeviceType());
        aliPushMessageDTO.setAccount(xpOperationsUser.getPhoneNumber());
        aliPushMessageDTO.setTitle("排班变更提示");
        aliPushMessageDTO.setBody(body.toJSONString());
        aliPushMessageDTO.setPushType("NOTICE");
        return aliPushMessageDTO;
    }
    /**
     * 构建消息存储
     * @param body
     * @param xpOperationsUser
     * @return
     */
    private XpOperationsUserNotification buildXpOperationsUserNotification(String message, String body, XpOperationsUser xpOperationsUser){
        XpOperationsUserNotification operationsUserNotification = new XpOperationsUserNotification();
        operationsUserNotification.setNotificationType(NotificationTypeEnum.SCHEDULE_CHANGED.getCode());
        operationsUserNotification.setNotificationContent(message);
        operationsUserNotification.setOperationsUserId(xpOperationsUser.getId());
        operationsUserNotification.setReadStatus(0);
        operationsUserNotification.setNotificationExt(body);
        return operationsUserNotification;
    }
    /**
     * 异步处理消息推送
     * @param pushMessage
     * @param notifications
     */
    private void pushMessage(List<AliPushMessageDTO> pushMessage, List<XpOperationsUserNotification> notifications) {
        if(pushMessage.isEmpty()){
            return;
        }
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
        executor.execute(() -> {
            xpOperationUserNotificationClient.addNotificationBatch(notifications);
            for (AliPushMessageDTO aliPushMessageDTO : pushMessage) {
                xpAliPushMessageClient.pushMessage(aliPushMessageDTO);
            }
        });
    }
    /**
     * 导出排班数据
     * @param month
     * @param response
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
@@ -949,6 +949,7 @@
            task.setVehicleLat(dto.getVehicleLat());
            task.setReportUserId(reportUserId);
            task.setReportTime(LocalDateTime.now());
            saveTask.add( task);
        }
        this.saveBatch(saveTask);
@@ -1246,16 +1247,19 @@
            }
            XpTaskHandleDetail xpTaskHandleDetail = xpTaskHandleDetailMapper.selectOne(new LambdaQueryWrapper<XpTaskHandleDetail>()
                    .eq(XpTaskHandleDetail::getTaskId, id));
            res.setDeathCount(xpTaskHandleDetail.getDeathCount());
            res.setSevereCount(xpTaskHandleDetail.getSevereCount());
            res.setMinorCount(xpTaskHandleDetail.getMinorCount());
            res.setResponsibilityJudgment(xpTaskHandleDetail.getResponsibilityJudgment());
            res.setResponsibleDescription(xpTaskHandleDetail.getResponsibleDescription());
            res.setResponsibleImage(xpTaskHandleDetail.getResponsibleImage());
            res.setDisposalDescription(xpTaskHandleDetail.getDisposalDescription());
            res.setDisposalImage(xpTaskHandleDetail.getDisposalImage());
            res.setSituationDescription(xpTaskHandleDetail.getSituationDescription());
            res.setSituationImage(xpTaskHandleDetail.getSituationImage());
            if (xpTaskHandleDetail != null){
                res.setDeathCount(xpTaskHandleDetail.getDeathCount());
                res.setSevereCount(xpTaskHandleDetail.getSevereCount());
                res.setMinorCount(xpTaskHandleDetail.getMinorCount());
                res.setResponsibilityJudgment(xpTaskHandleDetail.getResponsibilityJudgment());
                res.setResponsibleDescription(xpTaskHandleDetail.getResponsibleDescription());
                res.setResponsibleImage(xpTaskHandleDetail.getResponsibleImage());
                res.setDisposalDescription(xpTaskHandleDetail.getDisposalDescription());
                res.setDisposalImage(xpTaskHandleDetail.getDisposalImage());
                res.setSituationDescription(xpTaskHandleDetail.getSituationDescription());
                res.setSituationImage(xpTaskHandleDetail.getSituationImage());
            }
            managementDetailVO.setAccidentDetailVO(res);
        }
        return R.ok(managementDetailVO);
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpWorkOrderServiceImpl.java
@@ -17,6 +17,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -88,14 +89,25 @@
        }
        List<Long> handleUserIds = workOrderLogs.stream().map(XpWorkOrderLog::getHandleUserId).collect(Collectors.toList());
        List<SysUser> sysUsers = sysUserClient.listByIds(handleUserIds).getData();
        Map<Long, String> userMap = new HashMap<>();
        if (workOrder.getCreateById()!=null){
            List<Long> createUserId = new ArrayList<>();
            createUserId.add(workOrder.getCreateById());
            List<SysUser> sysUser = sysUserClient.listByIds(createUserId).getData();
            if (sysUser != null && !sysUser.isEmpty()){
                workOrder.setCreateByAvatar(sysUser.get(0).getAvatar());
            }
        }
        Map<Long, SysUser> userMap = new HashMap<>();
        if (sysUsers != null) {
            userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getId, SysUser::getNickName));
            userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getId, e->e));
        }
        for (XpWorkOrderLog workOrderLog : workOrderLogs) {
            if (workOrderLog.getHandleUserId() != null) {
                String handleUserName = userMap.get(workOrderLog.getHandleUserId());
                String handleUserName = userMap.get(workOrderLog.getHandleUserId()).getNickName();
                workOrderLog.setHandleUserName(handleUserName);
                String avatar = userMap.get(workOrderLog.getHandleUserId()).getAvatar();
                workOrderLog.setHandleUserAvatar(avatar);
            }
        }
        workOrder.setWorkOrderLogs(workOrderLogs);
@@ -108,11 +120,13 @@
        if (workOrderLog.getHandleType() == 2) {
            // 办结 工单状态流转为已完成
            workOrder.setHandleStatus(3);
            workOrder.setFeedbackUserPhone(null);
            workOrder.setHandleUserId(workOrderLog.getHandleUserId());
            this.updateById(workOrder);
        }else{
            // 移交
            workOrder.setHandleStatus(2);
            workOrder.setFeedbackUserPhone(null);
            workOrder.setHandleUserId(workOrderLog.getHandleUserId());
            this.updateById(workOrder);
        }
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpElectronicFenceManagementController.java
@@ -59,8 +59,8 @@
     */
    @PostMapping("/add")
    @ApiOperation(value = "新增电子围栏")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R add(@Validated @RequestBody ElectronicFenceAddDto dto) {
        return xpElectronicClient.add(dto);
@@ -74,8 +74,8 @@
    @PostMapping("/updateStatus")
    @ResponseBody
    @ApiOperation(value = "修改状态")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R updateStatus(@RequestBody ElectronicFenceAreaUpdateStatusDto dto) {
        return xpElectronicClient.updateStatus(dto);
@@ -97,8 +97,9 @@
    @PostMapping("/edit")
    @ResponseBody
    @ApiOperation(value = "编辑电子围栏")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)    public R edit(@Validated @RequestBody ElectronicFenceUpdateDto dto) {
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R edit(@Validated @RequestBody ElectronicFenceUpdateDto dto) {
        return xpElectronicClient.edit(dto);
    }
@@ -107,8 +108,8 @@
     */
    @PostMapping("/copy")
    @ApiOperation(value = "复制电子围栏")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R<Long> copy(@RequestParam("id") Integer id) {
        return xpElectronicClient.copy(id);
    }
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpPointManagementController.java
@@ -121,8 +121,8 @@
    @PostMapping("/add")
    @ApiOperation(value = "新增点位")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R add(@Validated  @RequestBody PointAddDto pointAddDto) {
        xpPointClient.add(pointAddDto);
        return R.ok();
@@ -131,9 +131,9 @@
     * 编辑点位
     */
    @PostMapping("/edit")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
    @ApiOperation(value = "编辑点位")
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R edit(@Validated@RequestBody PointUpdateDto pointAddDto) {
        xpPointClient.edit(pointAddDto);
        return R.ok();
@@ -142,10 +142,9 @@
     * 批量删除点位
     */
    @GetMapping("/deletePoint")
    @ResponseBody
    @ApiOperation(value = "删除点位")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R deletePoint(@RequestParam("ids") String ids) {
        xpPointClient.deletePoint(ids);
        return R.ok();
@@ -165,8 +164,8 @@
    @PostMapping("/enableDisable")
    @ResponseBody
    @ApiOperation(value = "启用/禁用")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R enableDisable(@RequestBody XpPointEnableDisableDto dto) {
        return xpPointClient.enableDisable(dto);
    }
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpElectronicFenceAreaController.java
@@ -4,11 +4,12 @@
import com.xiaopeng.api.model.operation.XpElectronicFenceArea;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.operation.service.IXpElectronicFenceAreaService;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@@ -20,8 +21,21 @@
 * @author mitao
 * @since 2026-02-03
 */
@Controller
@RequestMapping("/xp-electronic-fence-area")
@RestController
public class XpElectronicFenceAreaController {
    @Resource
    private IXpElectronicFenceAreaService xpElectronicFenceAreaService;
    /**
     * 根据区域ID查询区域信息
     *
     * @param id 区域ID
     * @return 区域信息
     */
    @ApiOperation(value = "根据区域ID查询区域信息", notes = "根据区域ID查询区域信息", tags = {"内部接口"})
    @PostMapping("/inner/v1/xp-electronic-fence-area/queryById/queryById")
    public R<XpElectronicFenceArea> queryById(@RequestParam("id") Long id) {
        return R.ok(xpElectronicFenceAreaService.getById(id));
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpElectronicFenceController.java
@@ -84,8 +84,8 @@
     */
    @PostMapping("/add")
    @ApiOperation(value = "新增电子围栏")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R add(@Validated @RequestBody ElectronicFenceAddDto dto) {
        return xpElectronicFenceService.addElectronic(dto);
    }
@@ -98,8 +98,8 @@
    @PostMapping("/updateStatus")
    @ResponseBody
    @ApiOperation(value = "修改状态")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R updateStatus(@RequestBody ElectronicFenceAreaUpdateStatusDto dto) {
        XpElectronicFenceArea electronicFenceArea = xpElectronicFenceAreaService.getById(dto.getId());
        if (electronicFenceArea == null) {
@@ -138,8 +138,8 @@
     */
    @PostMapping("/edit")
    @ApiOperation(value = "编辑电子围栏")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R edit(@Validated @RequestBody ElectronicFenceUpdateDto dto) {
        return xpElectronicFenceService.editElectronic(dto);
    }
@@ -149,8 +149,8 @@
     */
    @PostMapping("/copy")
    @ApiOperation(value = "复制电子围栏")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R<Long> copy(@RequestParam("id") Integer id) {
        XpElectronicFence electronicFence = xpElectronicFenceService.getById(id);
        if (electronicFence.getStatus()==2){
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpPointManagementController.java
@@ -85,9 +85,9 @@
     */
    @PostMapping("/addPoint")
    @ResponseBody
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
    @ApiOperation(value = "新增点位")
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R add(@Validated  @RequestBody PointAddDto pointAddDto) {
        XpPoint xpPoint = new XpPoint();
        BeanUtils.copyProperties(pointAddDto, xpPoint);
@@ -100,8 +100,8 @@
    @GetMapping("/deletePoint")
    @ResponseBody
    @ApiOperation(value = "删除点位")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R deletePoint(@RequestParam("ids") String ids) {
        xpPointService.removeBatchByIds(Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList()));
        return R.ok();
@@ -111,8 +111,8 @@
     */
    @PostMapping("/editPoint")
    @ApiOperation(value = "编辑点位")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R edit(@Validated@RequestBody PointUpdateDto pointAddDto) {
        XpPoint xpPoint = new XpPoint();
        BeanUtils.copyProperties(pointAddDto, xpPoint);
@@ -132,8 +132,8 @@
     */
    @PostMapping("/enableDisablePoint")
    @ApiOperation(value = "启用/禁用")
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
//    @Transactional
//    @ShardingSphereTransactionType(TransactionType.BASE)
    public R enableDisable(@RequestBody XpPointEnableDisableDto dto) {
        XpPoint xpPoint = xpPointService.getById(dto.getId());
        xpPoint.setOperationStatus(dto.getOperationStatus());
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpWhitelistController.java
@@ -117,6 +117,8 @@
        SysUser sysUser = tokenService.getLoginUser().getSysUser();
        XpWhitelist xpWhitelist = new XpWhitelist();
        BeanUtils.copyProperties(dto, xpWhitelist);
        xpWhitelist.setUpdateBy(tokenService.getLoginUser().getSysUser().getNickName());
        return xpWhitelistService.editWhitelist(xpWhitelist, sysUser);
    }
@@ -190,6 +192,7 @@
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @PostMapping("/importExcel")
    public AjaxResult<String> importExcel(@RequestPart("file") MultipartFile file) {
        ImportParams params = new ImportParams();
//        params.setTitleRows(1); // 标题行数
        params.setHeadRows(1); //表头行数
@@ -235,6 +238,7 @@
            xpWhitelist.setStatus(true);
            xpWhitelist.setIsPriorityDispatch(true);
            xpWhitelist.setWhitelistSource(1);
            xpWhitelist.setCreateBy(tokenService.getLoginUser().getSysUser().getNickName());
            addList.add(xpWhitelist);
        }
        if (!result.isEmpty()) {
@@ -250,6 +254,7 @@
        xpWhitelistOperlog.setOperationIp(IpUtils.getIpAddr());
        xpWhitelistOperlog.setOperationAccountId(sysUser.getId());
        xpWhitelistOperlog.setOperationContent(operationContent.toString());
        xpWhitelistOperlog.setCreateBy(tokenService.getLoginUser().getSysUser().getNickName());
        xpWhitelistOperlogService.save(xpWhitelistOperlog);
        return AjaxResult.success();
    }
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/exportExcle/XpWhitelistExportExcel.java
@@ -33,12 +33,12 @@
    private String account;
    @ApiModelProperty(value = "状态 0=冻结 1=正常")
    @cn.afterturn.easypoi.excel.annotation.Excel(name = "状态",width = 20,replace = {"true_正常","false_冻结"})
    @cn.afterturn.easypoi.excel.annotation.Excel(name = "状态",width = 20,replace = {"正常_true","冻结_false"})
    private Boolean status;
    @ApiModelProperty(value = "优先派单 1=是 0=否")
    @cn.afterturn.easypoi.excel.annotation.Excel(name = "优先派单",width = 20,replace = {"true_是","false_否"})
    @cn.afterturn.easypoi.excel.annotation.Excel(name = "优先派单",width = 20,replace = {"是_true","否_false"})
    private Boolean isPriorityDispatch;
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpWhitelistServiceImpl.java
@@ -53,6 +53,10 @@
    @Override
    public R addWhitelist(WhitelistAddDto dto, SysUser sysUser) {
        XpWhitelist old = this.lambdaQuery().eq(XpWhitelist::getAccount, dto.getAccount()).last("limit 1").one();
        if (old != null) {
            return R.fail("该账号已存在");
        }
        List<XpWhitelist> addList = new ArrayList<>();
        List<String> accounts = Arrays.asList(dto.getAccount().split(","));
        StringBuilder operationContent = new StringBuilder("新增账号:");
@@ -63,6 +67,7 @@
            xpWhitelist.setStatus(true);
            xpWhitelist.setIsPriorityDispatch(dto.getIsPriorityDispatch());
            xpWhitelist.setWhitelistSource(1);
            xpWhitelist.setCreateBy(sysUser.getCreateBy());
            addList.add(xpWhitelist);
            accountBuilder.append("\"").append(account).append("\"").append(",");
        }
xp-robotaxi-operation-boot/src/main/resources/mapper/operation/XpWhitelistMapper.xml
@@ -18,7 +18,7 @@
            and status = #{query.status}
        </if>
        <if test="query.whitelistSource != null">
            and whitelist_source = #{query.source}
            and whitelist_source = #{query.whitelistSource}
        </if>
        order by create_time desc
    </select>
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
@@ -270,7 +270,7 @@
     * @param dto 改派请求参数
     * @return 操作结果
     */
    @ApiOperation(value = "改派订单", tags = {"管理后台-交易管理-订单管理"},notes = "车辆列表在maintenance服务")
    @ApiOperation(value = "改派订单", tags = {"管理后台-交易管理-订单管理"},notes = "车辆列表在vehicleConvoy服务")
    @PostMapping("/api/v1/order/reassignById")
    public R<?> reassignById(@Validated @RequestBody XpOrderReassignDTO dto) {
        xpOrderService.reassignOrder(
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/AbstractJob.java
@@ -1,6 +1,10 @@
package com.xiaopeng.order.job.base;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.order.XpCruiseOrder;
import com.xiaopeng.order.service.IXpCruiseOrderService;
import com.xiaopeng.order.service.IXpOrderService;
import com.xiaopeng.order.job.utils.SpringContextsUtil;
import com.xiaopeng.order.service.XpOrderTimeoutLogService;
@@ -19,7 +23,9 @@
    protected IXpOrderService xpOrderService;
    protected XpPushMessageClient xpPushMessageClient;
    protected XpOrderTimeoutLogService xpOrderTimeoutLogService;
    protected IXpCruiseOrderService xpCruiseOrderService;
    protected OrderMissionClient orderMissionClient;
    protected XpVehicleClient xpVehicleClient;
    public AbstractJob(){
        this.xpOrderService = SpringContextsUtil.getBean(IXpOrderService.class);
        this.xpPushMessageClient = SpringContextsUtil.getBean(XpPushMessageClient.class);
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/TimeJobType.java
@@ -6,6 +6,7 @@
 */
public enum TimeJobType {
    ORDER_CANCEL("order_cancel","订单取消"),
    ADD_CRUISE_MISSION("add_cruise_mission","添加巡游任务"),
    END_TRIP("end_trip","自动结束行程");
    private String type;
    private String desc;
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/AddCruiseMissionJob.java
New file
@@ -0,0 +1,43 @@
package com.xiaopeng.order.job.jobs;
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.model.order.XpCruiseOrder;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.order.job.base.AbstractJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Objects;
/**
 * 推送定时任务
 * @author Administrator
 *
 */
@Slf4j
public class AddCruiseMissionJob extends AbstractJob {
    public static final String name = "addCruiseMission_";
    @Override
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        JobDataMap maps = context.getMergedJobDataMap();
        Long orderId = maps.getLong("id");
        try {
            log.info("开始执行添加任务");
            XpCruiseOrder xpCruiseOrder = xpCruiseOrderService.getById(orderId);
            R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(xpCruiseOrder.getVehicleId());
            if(xpVehicleR.getData().getState()==0){
                orderMissionClient.pushOrder(new PushOrderDto(xpCruiseOrder.getVehicleVin(),xpCruiseOrder.getId(),null));
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -28,15 +28,19 @@
import com.xiaopeng.api.feignClient.account.XpAppUserClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.maintenance.XpTaskRuleClient;
import com.xiaopeng.api.feignClient.operation.XpCruisePlanClient;
import com.xiaopeng.api.feignClient.operation.XpPointClient;
import com.xiaopeng.api.feignClient.operation.XpPricingClient;
import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient;
import com.xiaopeng.api.feignClient.order.XpCruiseOrderClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.account.XpAppUser;
import com.xiaopeng.api.model.maintenance.XpTaskRule;
import com.xiaopeng.api.model.operation.XpFeedbackType;
import com.xiaopeng.api.model.operation.XpGeoQueryEntity;
import com.xiaopeng.api.model.operation.XpPoint;
@@ -69,6 +73,7 @@
import com.xiaopeng.order.dto.MileageDto;
import com.xiaopeng.order.job.base.QuartzManager;
import com.xiaopeng.order.job.base.TimeJobType;
import com.xiaopeng.order.job.jobs.AddCruiseMissionJob;
import com.xiaopeng.order.job.jobs.EndTripJob;
import com.xiaopeng.order.job.jobs.OrderCancelJob;
import com.xiaopeng.order.mangodb.model.OrderTrajectory;
@@ -100,6 +105,7 @@
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@@ -144,6 +150,8 @@
    private final OrderMissionClient orderMissionClient;
    private final XpOrderDetailMapper xpOrderDetailMapper;
    private final XpCruiseOrderMapper xpCruiseOrderMapper;
    private final XpTaskRuleClient xpTaskRuleClient;
    private final XpCruisePlanClient xpCruisePlanClient;
    @Autowired
@@ -511,7 +519,20 @@
        orderCancel.setCancelReason("运营人员取消订单");
        orderCancel.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
        xpOrderCancelService.save(orderCancel);
        //查询车辆信息
        R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(order.getId());
        if (xpVehicleR.getCode() == HttpStatus.SUCCESS && Objects.nonNull(xpVehicleR.getData())) {
            // 下发命令
            if (order.getStatus() > 1) {
                PushOrderDto pushOrderDto = new PushOrderDto();
                pushOrderDto.setOrderId(order.getId().toString());
                pushOrderDto.setVin(xpVehicleR.getData().getVehicleVin());
                pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
                orderMissionClient.cancelOrder(pushOrderDto);
            }
        } else {
            log.info("查询车辆信息失败,订单ID: {}, 下发取消订单命令失败", order.getId());
        }
        log.info("订单取消成功,订单ID: {}, 操作人: {}", order.getId(), SecurityUtils.getUsername());
    }
@@ -538,10 +559,10 @@
            throw new ServiceException("订单不存在");
        }
        // 2. 校验订单状态(只有待接单、待出发、接驾中状态可以改派)
        // 2. 校验订单状态(只有待出发、接驾中、待乘客上车状态可以改派)
        Integer currentStatus = order.getStatus();
        if (currentStatus != 1 && currentStatus != 2 && currentStatus != 3) {
            throw new ServiceException("当前订单状态不允许改派,只有待接单、待出发、接驾中状态的订单可以改派", I18nKeyConstant.ORDER_REASSIGN_FAILED);
        if (currentStatus != 2 && currentStatus != 3 && currentStatus != 4) {
            throw new ServiceException("当前订单状态不允许改派,只有待出发、接驾中、待乘客上车状态的订单可以改派", I18nKeyConstant.ORDER_REASSIGN_FAILED);
        }
        // 3. 校验新旧车辆是否相同
@@ -580,6 +601,47 @@
        // 6. 保存原车辆和车队信息
        Long oldVehicleId = order.getVehicleId();
        Long oldFleetId = order.getFleetId();
        // 6.1 处理原车辆:取消订单指令、解绑乘客、更新状态、创建返程巡游订单
        if (Objects.nonNull(oldVehicleId)) {
            try {
                R<XpVehicle> oldVehicleResult = xpVehicleClient.queryById(oldVehicleId);
                if (oldVehicleResult != null && oldVehicleResult.getCode() == HttpStatus.SUCCESS && oldVehicleResult.getData() != null) {
                    XpVehicle oldVehicle = oldVehicleResult.getData();
                    // 6.1.1 取消原订单指令
                    PushOrderDto cancelDto = new PushOrderDto();
                    cancelDto.setOrderId(order.getId().toString());
                    cancelDto.setVin(oldVehicle.getVehicleVin());
                    cancelDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
                    orderMissionClient.cancelOrder(cancelDto);
                    log.info("已取消原车辆订单指令,订单ID: {}, VIN: {}", orderId, oldVehicle.getVehicleVin());
                    // 6.1.2 解绑乘客与原车辆关系
                    if (Objects.nonNull(order.getAppUserId())) {
                        CancelTaxiPassengerVo cancelVo = new CancelTaxiPassengerVo();
                        cancelVo.setVin(oldVehicle.getVehicleVin());
                        cancelVo.setUid(order.getAppUserId().toString());
                        cancelVo.setOrderNo(order.getOrderNumber());
                        cancelVo.setAppId("");
                        userVehicleClient.cancelTaxiPassenger(cancelVo);
                        log.info("已解绑乘客与原车辆关系,用户ID: {}, VIN: {}", order.getAppUserId(), oldVehicle.getVehicleVin());
                    }
                    // 6.1.3 修改原车辆状态为空闲
                    oldVehicle.setState(0);
                    xpVehicleClient.updateVehicleById(oldVehicle);
                    log.info("已将原车辆状态设为空闲,车辆ID: {}", oldVehicleId);
                    // 6.1.4 为原车辆创建返程巡游订单
                    createReturnCruiseOrder(oldVehicle, order);
                } else {
                    log.warn("查询原车辆信息失败,车辆ID: {}", oldVehicleId);
                }
            } catch (Exception e) {
                log.error("处理原车辆失败,车辆ID: {},错误: {}", oldVehicleId, e.getMessage());
            }
        }
        // 7. 查询新车辆关联的车队ID
        Long newFleetId = null;
@@ -634,7 +696,118 @@
        log.info("订单改派成功,订单ID: {}, 原车辆ID: {}, 新车辆ID: {}, 原车队ID: {}, 新车队ID: {}, 操作人: {}",
                orderId, oldVehicleId, newVehicleId, oldFleetId, newFleetId, SecurityUtils.getUsername());
        //推送消息
        // 11. 处理新车辆:绑定乘客、下发订单、更新状态
        try {
            // 11.1 绑定乘客与新车辆关系
            if (Objects.nonNull(order.getAppUserId())) {
                AddTaxiPassengerVo addVo = new AddTaxiPassengerVo();
                addVo.setVin(newVehicle.getVehicleVin());
                addVo.setUid(order.getAppUserId().toString());
                addVo.setOrderNo(order.getOrderNumber());
                addVo.setAppId(""); // TODO 获取appId
                userVehicleClient.addTaxiPassenger(addVo);
                log.info("已绑定乘客与新车辆关系,用户ID: {}, VIN: {}", order.getAppUserId(), newVehicle.getVehicleVin());
            }
            // 11.2 下发订单到新车辆
            PushOrderDto pushDto = new PushOrderDto();
            pushDto.setOrderId(order.getId().toString());
            pushDto.setVin(newVehicle.getVehicleVin());
            orderMissionClient.pushOrder(pushDto);
            log.info("已下发订单到新车辆,订单ID: {}, VIN: {}", orderId, newVehicle.getVehicleVin());
            // 11.3 更新新车辆状态为已接单
            newVehicle.setState(1);
            xpVehicleClient.updateVehicleById(newVehicle);
            log.info("已将新车辆状态设为已接单,车辆ID: {}", newVehicleId);
        } catch (Exception e) {
            log.error("处理新车辆失败,车辆ID: {},错误: {}", newVehicleId, e.getMessage());
        }
    }
    /**
     * 为原车辆创建返程巡游订单
     * <p>
     * 改派时,原车辆需要返回巡游路线:
     * - 若最新巡游订单状态为已终止(status=2),返回原出发点
     * - 若最新巡游订单状态为已完成(status=3),返回原终点
     * - 其他状态,默认返回原出发点
     * </p>
     *
     * @param oldVehicle 原车辆信息
     * @param order      当前订单信息
     */
    private void createReturnCruiseOrder(XpVehicle oldVehicle, XpOrder order) {
        try {
            // 查询该车辆最新的一条巡游订单
            XpCruiseOrder lastCruise = xpCruiseOrderMapper.selectOne(
                    new LambdaQueryWrapper<XpCruiseOrder>()
                            .eq(XpCruiseOrder::getVehicleId, oldVehicle.getId())
                            .orderByDesc(BaseModel::getCreateTime)
                            .last("limit 1")
            );
            if (lastCruise == null) {
                log.warn("原车辆没有巡游订单记录,跳过创建返程订单,车辆ID: {}", oldVehicle.getId());
                return;
            }
            XpCruiseOrder returnOrder = new XpCruiseOrder();
            returnOrder.setId("XU" + IdUtil.fastUUID());
            returnOrder.setVehicleId(oldVehicle.getId());
            returnOrder.setVehicleVin(oldVehicle.getVehicleVin());
            returnOrder.setFleetId(oldVehicle.getFleetId());
            returnOrder.setOrderType(2); // 返程单
            returnOrder.setStatus(1);    // 进行中
            returnOrder.setLastOrderId(lastCruise.getId());
            returnOrder.setCreateTime(LocalDateTime.now());
            // 返程起点 = 当前订单的终点(车辆当前位置附近)
            returnOrder.setStartPointId(order.getEndPointId());
            returnOrder.setStartPointName(order.getEndPointName());
            returnOrder.setStartLon(order.getEndLon());
            returnOrder.setStartLat(order.getEndLat());
            // 根据最新巡游订单状态决定返程终点
            if (lastCruise.getStatus() != null && lastCruise.getStatus() == 2) {
                // 已终止(status=2) -> 返回原出发点
                returnOrder.setEndPointId(lastCruise.getStartPointId());
                returnOrder.setEndPointName(lastCruise.getStartPointName());
                returnOrder.setEndLon(lastCruise.getStartLon());
                returnOrder.setEndLat(lastCruise.getStartLat());
                log.info("巡游订单状态为已终止,返回原出发点");
            } else if (lastCruise.getStatus() != null && lastCruise.getStatus() == 3) {
                // 已完成(status=3) -> 返回原终点
                returnOrder.setEndPointId(lastCruise.getEndPointId());
                returnOrder.setEndPointName(lastCruise.getEndPointName());
                returnOrder.setEndLon(lastCruise.getEndLon());
                returnOrder.setEndLat(lastCruise.getEndLat());
                log.info("巡游订单状态为已完成,返回原终点");
            } else {
                // 其他状态(进行中等),默认返回原出发点
                returnOrder.setEndPointId(lastCruise.getStartPointId());
                returnOrder.setEndPointName(lastCruise.getStartPointName());
                returnOrder.setEndLon(lastCruise.getStartLon());
                returnOrder.setEndLat(lastCruise.getStartLat());
                log.info("巡游订单状态为{},默认返回原出发点", lastCruise.getStatus());
            }
            xpCruiseOrderMapper.insert(returnOrder);
            // 下发巡游订单到原车辆
            PushOrderDto pushDto = new PushOrderDto();
            pushDto.setVin(oldVehicle.getVehicleVin());
            pushDto.setOrderId(returnOrder.getId());
            orderMissionClient.pushOrder(pushDto);
            log.info("为原车辆创建返程巡游订单成功,订单ID: {}, 车辆ID: {}", returnOrder.getId(), oldVehicle.getId());
        } catch (Exception e) {
            log.error("创建返程巡游订单失败,车辆ID: {},错误: {}", oldVehicle.getId(), e.getMessage());
        }
    }
    @Override
@@ -1238,7 +1411,7 @@
            useUserCouponDto.setUserCouponId(order.getCouponId());
            xpAppUserCouponClient.useUserCoupon(useUserCouponDto);
        }
// 计算完价格后 挑选优惠券
       // 计算完价格后 挑选优惠券
        GetUserCouponDto getUserCouponDto = new GetUserCouponDto();
        getUserCouponDto.setUserId(Long.valueOf(uid));
        getUserCouponDto.setTotalAmount(order.getOrderMoney().doubleValue());
@@ -1250,10 +1423,28 @@
        }
        order.setAppUserId(null);
        baseMapper.updateById(order);
        // 结束后的车辆操作
        if(vehicle!=null){
            // 修改车辆状态
            vehicle.setState(0);
            // 获取配置 根据配置判断是否该收车 如果是则找到收车点位进行收车操作
            R<XpTaskRule> xpTaskRuleR = xpTaskRuleClient.queryDetail();
            XpTaskRule xpTaskRule = xpTaskRuleR.getData();
            // 生成新的巡游单子 回到最新巡游的初始起点位置
            XpCruiseOrder xpCruiseOrders = xpCruiseOrderMapper.selectOne(new LambdaQueryWrapper<XpCruiseOrder>().eq(XpCruiseOrder::getVehicleId, vehicle.getId()).eq(XpCruiseOrder::getStatus, 2).orderByDesc(BaseModel::getCreateTime).last("limit 1"));
            int temp=0;
            if(xpCruiseOrders==null){
                temp=1;
                //特殊情况 可能没有产生终止的订单  (到站点就被正常接单了)所以找正常订单
                xpCruiseOrders=xpCruiseOrderMapper.selectOne(new LambdaQueryWrapper<XpCruiseOrder>().eq(XpCruiseOrder::getVehicleId, vehicle.getId()).eq(XpCruiseOrder::getStatus, 3).orderByDesc(BaseModel::getCreateTime).last("limit 1"));
            }
            XpCruiseOrder xpCruiseOrder = new XpCruiseOrder();
            xpCruiseOrder.setVehicleId(vehicle.getId());
            xpCruiseOrder.setFleetId(vehicle.getFleetId());
@@ -1265,19 +1456,54 @@
            xpCruiseOrder.setStartLon(order.getEndLon());
            xpCruiseOrder.setStartLat(order.getEndLat());
            xpCruiseOrder.setEndPointId(xpCruiseOrders.getStartPointId());
            xpCruiseOrder.setEndPointName(xpCruiseOrders.getStartPointName());
            xpCruiseOrder.setEndLon(xpCruiseOrders.getStartLon());
            xpCruiseOrder.setEndLat(xpCruiseOrders.getStartLat());
            // 完成的直接走终点   终止的走起点
            if(temp==0){
                xpCruiseOrder.setEndPointId(xpCruiseOrders.getStartPointId());
                xpCruiseOrder.setEndPointName(xpCruiseOrders.getStartPointName());
                xpCruiseOrder.setEndLon(xpCruiseOrders.getStartLon());
                xpCruiseOrder.setEndLat(xpCruiseOrders.getStartLat());
            }else {
                xpCruiseOrder.setEndPointId(xpCruiseOrders.getEndPointId());
                xpCruiseOrder.setEndPointName(xpCruiseOrders.getEndPointName());
                xpCruiseOrder.setEndLon(xpCruiseOrders.getEndLon());
                xpCruiseOrder.setEndLat(xpCruiseOrders.getEndLat());
            }
            xpCruiseOrder.setStatus(1);
            xpCruiseOrder.setLastOrderId(xpCruiseOrders.getId());
            xpCruiseOrder.setCreateTime(LocalDateTime.now());
            xpCruiseOrder.setId("XU"+ IdUtil.fastUUID());
            // 判断当前时分秒是否大于收车时间
            LocalTime vehicleCollectionTime = xpTaskRule.getVehicleCollectionTime();
            if (vehicleCollectionTime.isBefore(LocalTime.now())) {
                vehicle.setOperatingStatus(3);
                //找到车辆的收车点位 更新终点点位
                R<XpCruiseOrder> returnCruisePoint = xpCruisePlanClient.findReturnCruisePoint(xpCruiseOrder);
                xpCruiseOrder = returnCruisePoint.getData();
            }
            xpVehicleClient.updateVehicleById(vehicle);
            xpCruiseOrderMapper.insert(xpCruiseOrder);
            R<XpPoint> xpPointR = xpPointClient.queryById(order.getEndPointId());
            XpPoint data = xpPointR.getData();
            //下发命令
            orderMissionClient.pushOrder(new PushOrderDto(vehicle.getVehicleVin(),xpCruiseOrder.getId(),null));
            // 添加自动结束行程定时任务job
            Map<String, ? extends Object> jobMaps =
                    new ImmutableMap.Builder<String, String>().
                            put("id", xpCruiseOrder.getId())
                            .build();
            QuartzManager.addJob(
                    AddCruiseMissionJob.class,
                    (AddCruiseMissionJob.name + xpCruiseOrder.getId()).toUpperCase(),
                    TimeJobType.ADD_CRUISE_MISSION,
                    DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(data.getParkingTimeLimit())),
                    jobMaps
            );
        }
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -479,8 +479,9 @@
     */
    @ApiOperation(value = "查询可改派的车辆列表", tags = {"管理后台-订单管理"})
    @GetMapping("/api/v1/vehicle/availableList")
    public R<List<XpVehicle>> listAvailableVehicles() {
        List<XpVehicle> list = xpVehicleService.listAvailableVehicles();
    @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataTypeClass = Long.class)
    public R<List<XpVehicle>> listAvailableVehicles(@RequestParam Long orderId) {
        List<XpVehicle> list = xpVehicleService.listAvailableVehicles(orderId);
        return R.ok(list);
    }
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java
@@ -33,7 +33,7 @@
     *
     * @return 车辆列表
     */
    List<XpVehicle> listAvailableVehicles();
    List<XpVehicle> listAvailableVehicles(Long orderId);
    /**
     * 查询车辆列表接口-地图
xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -11,6 +11,7 @@
import com.xiaopeng.api.feignClient.operation.XpElectronicClient;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpElectronicFenceArea;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicleAnnualRecord;
@@ -83,22 +84,45 @@
    }
    @Override
    public List<XpVehicle> listAvailableVehicles() {
        // 构建查询条件
        LambdaQueryWrapper<XpVehicle> wrapper = new LambdaQueryWrapper<>();
    public List<XpVehicle> listAvailableVehicles(Long orderId) {
        // 1. 通过订单ID查询订单信息,获取区域ID
        R<XpOrder> orderResult = xpOrderClient.queryOrderById(orderId);
        if (orderResult == null || orderResult.getData() == null) {
            log.warn("查询订单失败,orderId: {}", orderId);
            return Collections.emptyList();
        }
        // 必要条件:可改派车辆的4个核心条件
        wrapper.ne(XpVehicle::getStatus, 3)  // 状态不是保险/年检过期
               .isNotNull(XpVehicle::getStatus)
               .eq(XpVehicle::getOperatingStatus, 1)  // 运营中
               .eq(XpVehicle::getAcceptOrTest, 1)  // 接单模式
               .eq(XpVehicle::getAcceptOrTestStatus, 1);  // 开始接单
        XpOrder order = orderResult.getData();
        Long areaId = order.getXpElectronicFenceAreaId();
        if (areaId == null) {
            log.warn("订单区域ID为空,orderId: {}", orderId);
            return Collections.emptyList();
        }
        // 2. 通过区域ID查询围栏ID
        R<XpElectronicFenceArea> areaResult = xpElectronicClient.queryElectronicFenceAreaById(areaId);
        if (areaResult == null || areaResult.getData() == null) {
            log.warn("查询围栏区域失败,areaId: {}", areaId);
            return Collections.emptyList();
        }
        Long electronicId = areaResult.getData().getElectronicId();
        if (electronicId == null) {
            log.warn("围栏ID为空,areaId: {}", areaId);
            return Collections.emptyList();
        }
        // 3. 根据围栏ID查询车辆列表 (operatingStatus=1 且 state=0)
        LambdaQueryWrapper<XpVehicle> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(XpVehicle::getElectronicId, electronicId)
               .eq(XpVehicle::getOperatingStatus, 1)
               .eq(XpVehicle::getState, 0);
        // 排序:按电量降序、入库时间降序
        wrapper.orderByDesc(XpVehicle::getCurrentElectricity)
               .orderByDesc(XpVehicle::getWarehousingTime);
        // 执行查询
        return this.list(wrapper);
    }
xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages.properties
@@ -1,7 +1,7 @@
# 中文
fleet.operation.user.bound.v2=当前车队已和该人员关联
policy.application.audit.ids.notEmpty=保单申请ID列表不能为空
fleet.user.bound=运维人员[{0}]已绑定车队[{1}]
fleet.operation.user.bound.v1=运维人员[{0}]已绑定车队[{1}]
fleet.vehicle.bound.v2=当前车队已和该车辆关联
fleet.vehicle.bound.v1=车辆[{0}]已绑定车队[{1}]
policy.application.audit.status.notNull=保单审核状态不能为空
xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages_zh_CN.properties
@@ -2,6 +2,7 @@
fleet.operation.user.bound.v2=当前车队已和该人员关联
policy.application.audit.ids.notEmpty=保单申请ID列表不能为空
fleet.user.bound=运维人员[{0}]已绑定车队[{1}]
fleet.operation.user.bound.v1=运维人员[{0}]已绑定车队[{1}]
fleet.vehicle.bound.v2=当前车队已和该车辆关联
policy.application.audit.status.notNull=保单审核状态不能为空
welcome.message=欢迎来到我们的应用程序!