From 3cc3d0a10593c109a015d01ee05de8da73443778 Mon Sep 17 00:00:00 2001
From: xuhy <3313886187@qq.com>
Date: 星期二, 14 四月 2026 20:39:03 +0800
Subject: [PATCH] [feat]事故任务分派逻辑完善、转派工单

---
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java |   95 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
index 781587e..aa94db6 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
+++ b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
@@ -7,10 +7,12 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.Lists;
+import com.xiaopeng.api.dto.account.XpOperationsUserPositionDTO;
 import com.xiaopeng.api.dto.pushMessage.AliPushMessageDTO;
 import com.xiaopeng.api.feignClient.account.SysUserClient;
 import com.xiaopeng.api.feignClient.account.XpOperationUserClient;
 import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient;
+import com.xiaopeng.api.feignClient.operation.SmsClient;
 import com.xiaopeng.api.feignClient.pushMessage.XpAliPushMessageClient;
 import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetOperationsClient;
 import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient;
@@ -23,6 +25,7 @@
 import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
 import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
 import com.xiaopeng.api.vo.maintenance.TaskScheduleConstants;
+import com.xiaopeng.api.vo.operation.SmsVo;
 import com.xiaopeng.common.core.constant.AliPushTypeConstant;
 import com.xiaopeng.common.core.domain.R;
 import com.xiaopeng.common.core.enums.NotificationTypeEnum;
@@ -42,6 +45,7 @@
 import com.xiaopeng.maintenance.model.query.WorkBenchQuery;
 import com.xiaopeng.maintenance.model.query.XpTaskRecordPageQuery;
 import com.xiaopeng.maintenance.model.vo.*;
+import com.xiaopeng.maintenance.repo.XpOperationsUserRepository;
 import com.xiaopeng.maintenance.service.IXpTaskRuleRoleService;
 import com.xiaopeng.maintenance.service.IXpTaskRuleService;
 import com.xiaopeng.maintenance.service.XpTaskService;
@@ -58,6 +62,8 @@
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+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;
@@ -1361,6 +1367,43 @@
         return this.baseMapper.queryInfoByVehicleId(vehicleId);
     }
 
+
+    @Autowired
+    private XpOperationsUserRepository repository;
+
+    public void reassign(Long taskId,String msg) {
+
+        XpTask task = getById(taskId);
+        XpVehicle vehicle = xpVehicleClient.queryById(task.getVehicleId()).getData();
+        XpTaskRule taskRule = xpTaskRuleService.lambdaQuery().last("limit 1").one();
+        List<XpTaskRuleRole> taskRuleRole = xpTaskRuleRoleService.lambdaQuery().eq(XpTaskRuleRole::getRuleType, 9).list();
+        if (Objects.isNull(taskRuleRole) || Objects.isNull(taskRule)) {
+            throw new ServiceException("未配置车辆事故任务分配规则");
+        }
+        Long fleetId = xpFleetVehicleClient.getFleetIdByVehicleId(vehicle.getId()).getData();
+        List<Long> roleIds = taskRuleRole.stream().map(XpTaskRuleRole::getRoleId).collect(Collectors.toList());
+        List<XpOperationsRole> data = xpOperationUserClient.getXpOperationsRoleByRoleIds(roleIds).getData();
+        List<Long> ids = xpFleetOperationsClient.getOperationsIdsByFleetId(fleetId).getData();
+        List<XpOperationsRole> collect = data.stream().filter(x -> ids.contains(x.getOperationsUserId())).collect(Collectors.toList());
+        String belongUserIds = collect.stream().map(XpOperationsRole::getOperationsUserId).collect(Collectors.toSet()).stream().map(String::valueOf).collect(Collectors.joining(","));
+        String idsWithoutMe = belongUserIds.replace(task.getHandleUserId(), "");
+        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vehicle.getVehicleVin())), VehiclePosition.class);
+        String handlerUser = chooseNearestAvailableOperationsUser(idsWithoutMe, vehiclePosition);
+        task.setHandleUserId(handlerUser);
+        if(handlerUser == null) {
+            task.setStatus(4);
+            noticeAdministrator(task);
+        }
+        updateById(task);
+        // 存储事故处理日志
+        XpTaskHandleDetail xpTaskHandleDetail = new XpTaskHandleDetail();
+        xpTaskHandleDetail.setTaskId(task.getId());
+        xpTaskHandleDetail.setResponsibleDescription(msg);
+        xpTaskHandleDetailMapper.insert(xpTaskHandleDetail);
+        sendAccidentNotificationAsync(task, vehicle.getPlateNumber(), taskRule.getProcessingTimeLimit());
+    }
+
+
     @Override
     public void saveVehicleAccidentError(Long vehicleId) {
         XpVehicle vehicle = xpVehicleClient.queryById(vehicleId).getData();
@@ -1369,8 +1412,6 @@
         if (Objects.isNull(taskRuleRole) || Objects.isNull(taskRule)) {
             throw new ServiceException("未配置车辆事故任务分配规则");
         }
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
-        //查找事故处理人,处理角色和车辆所属的车队
         Long fleetId = xpFleetVehicleClient.getFleetIdByVehicleId(vehicle.getId()).getData();
         List<Long> roleIds = taskRuleRole.stream().map(XpTaskRuleRole::getRoleId).collect(Collectors.toList());
         List<XpOperationsRole> data = xpOperationUserClient.getXpOperationsRoleByRoleIds(roleIds).getData();
@@ -1383,7 +1424,7 @@
         String address = geocode.get("address");
 
         XpTask task = new XpTask();
-        String taskCode = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5);
+        String taskCode = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + UUIDUtil.getNumberRandom(5);
         task.setTaskCode(taskCode);
         task.setTaskCategory(TaskScheduleConstants.TASK_CATEGORY_ACCIDENT);
         task.setTaskTypeId("8,10");
@@ -1394,7 +1435,12 @@
         task.setVehicleLocation(address);
         task.setVehicleLat(new BigDecimal(vehiclePosition.getPoint().getY()));
         task.setVehicleLon(new BigDecimal(vehiclePosition.getPoint().getX()));
-        task.setHandleUserId(belongUserIds);
+        String handlerUser = chooseNearestAvailableOperationsUser(belongUserIds, vehiclePosition);
+        task.setHandleUserId(handlerUser);
+        if(handlerUser == null) {
+            task.setStatus(4);
+            noticeAdministrator(task);
+        }
         task.setAssigneeTime(LocalDateTime.now());
         task.setReportUserId(0L);
         task.setReportTime(LocalDateTime.now());
@@ -1409,6 +1455,47 @@
         sendAccidentNotificationAsync(task, vehicle.getPlateNumber(), taskRule.getProcessingTimeLimit());
     }
 
+    @Value("${robotaxi.sms.app-id:1476153389173952512}")
+    private String smsAppId;
+    @Value("${robotaxi.sms.app-push-config-code:ROBOTAXI_VERIFY_CODE_SMS}")
+    private String ROBOTAXI_VERIFY_CODE_SMS_TPL;
+    @Resource
+    private SmsClient smsClient;
+    private void noticeAdministrator(XpTask task) {
+
+        SmsVo smsVo = new SmsVo();
+        smsVo.setAppId(smsAppId);
+        smsVo.setParams(Collections.EMPTY_MAP);
+        smsVo.setTemplateCode(ROBOTAXI_VERIFY_CODE_SMS_TPL);
+
+        String adminPhone = "139..";
+
+        smsVo.setReceivers(adminPhone);
+        smsClient.pushSms(smsVo);
+
+    }
+
+    private String chooseNearestAvailableOperationsUser(String belongUserIds, VehiclePosition vehiclePosition) {
+
+        List<Long> ids = Arrays.stream(belongUserIds.split(",")).filter(StringUtils::isNotBlank).map(Long::valueOf).collect(Collectors.toList());
+
+        // 让mongo根据[id in ids]返回距离排序的users
+//        List<XpOperationsUserPositionDTO> users = mongoTemplate.find(new Query(Criteria.where("_id").in(ids)), XpOperationsUserPositionDTO.class);
+
+        List<XpOperationsUserPositionDTO> XpOperationsUserPositionDTOs = repository.findWithDistance(new Point(vehiclePosition.getPoint().getX(), vehiclePosition.getPoint().getY()), 1000, ids);
+        boolean skipBusy = false;//TODO 获取系统配置,是否开启跳过忙碌
+        List<XpOperationsUserPositionDTO> candidates = XpOperationsUserPositionDTOs.stream()
+                .filter(positionDTO -> skipBusy && positionDTO.getStatus() == 1)
+                .sorted(Comparator.comparing(XpOperationsUserPositionDTO::getDistance))
+                .collect(Collectors.toList());
+
+        if (candidates.isEmpty()) return null;
+
+        return String.valueOf(candidates.get(0).getId());
+    }
+
+
+
     @Override
     public R assigneeTask(Long id, Long handlerUserId, Long assigneeUserId) {
         XpTask task = this.getById(id);

--
Gitblit v1.7.1