liujie
2026-06-09 c96fbe6b0aeb413a17c429133ee6d81d138144b9
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
@@ -40,10 +40,12 @@
import com.xiaopeng.common.core.enums.TaskTypeEnum;
import com.xiaopeng.common.core.enums.TaskTypeNotificationEnum;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.SensitiveDataCryptoUtil;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.evi.oss.service.AliOssService;
import com.xiaopeng.maintenance.constant.I18nKeyConstant;
import com.xiaopeng.maintenance.dto.HandleVehicleAccidentDto;
import com.xiaopeng.maintenance.dto.SaveRemoteDrivingAccidentDto;
import com.xiaopeng.maintenance.dto.SaveErrorTaskDto;
import com.xiaopeng.maintenance.dto.SaveRoutineDetailDto;
import com.xiaopeng.maintenance.dto.SaveVehicleAccidentDto;
@@ -258,24 +260,25 @@
        if (Objects.isNull(vehicle)) {
            throw new ServiceException("上报失败,未获取到车辆信息", I18nKeyConstant.TASK_VEHICLE_NOT_EXIST);
        }
        // VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vehicle.getVehicleVin())), VehiclePosition.class);
        // if (Objects.isNull(vehiclePosition)) {
        //     log.error("事故上报未获取到车辆当前定位");
        //     throw new ServiceException("获取车辆实时定位信息失败,请稍后重试", I18nKeyConstant.TASK_SAVE_ERROR);
        // }
        // xpTask.setVehicleLon(new BigDecimal(vehiclePosition.getPoint().getX()));
        // xpTask.setVehicleLat(new BigDecimal(vehiclePosition.getPoint().getY()));
        // Map<String, String> geocode = gdMapGeocodingUtil.geocode(xpTask.getVehicleLon().toString(), xpTask.getVehicleLat().toString());
        // String address = geocode == null ? null : geocode.get("address");
        // if (StringUtils.isBlank(address)) {
        //     log.error("事故上报通过车辆定位从高德获取地址信息失败");
        //     throw new ServiceException("获取车辆实时定位信息失败,请稍后重试", I18nKeyConstant.TASK_SAVE_ERROR);
        // }
        // xpTask.setVehicleLocation(address);
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
        if (Objects.isNull(vehiclePosition)) {
            log.error("事故上报未获取到车辆当前定位");
            throw new ServiceException("获取车辆实时定位信息失败,请稍后重试", I18nKeyConstant.TASK_SAVE_ERROR);
        }
        xpTask.setVehicleLon(new BigDecimal(vehiclePosition.getPoint().getX()));
        xpTask.setVehicleLat(new BigDecimal(vehiclePosition.getPoint().getY()));
        Map<String, String> geocode = gdMapGeocodingUtil.geocode(xpTask.getVehicleLon().toString(), xpTask.getVehicleLat().toString());
        String address = geocode == null ? null : geocode.get("address");
        if (StringUtils.isBlank(address)) {
            log.error("事故上报通过车辆定位从高德获取地址信息失败");
            throw new ServiceException("获取车辆实时定位信息失败,请稍后重试", I18nKeyConstant.TASK_SAVE_ERROR);
        }
        xpTask.setVehicleLocation(address);
// 临时处理
        xpTask.setVehicleLon(new BigDecimal("104.055683"));
        xpTask.setVehicleLat(new BigDecimal("30.585991"));
        xpTask.setVehicleLocation("四川省成都市武侯区石羊街道天府新谷");
//        xpTask.setVehicleLon(new BigDecimal("104.055683"));
//        xpTask.setVehicleLat(new BigDecimal("30.585991"));
//        xpTask.setVehicleLocation("四川省成都市武侯区石羊街道天府新谷");
        xpTask.setVehicleId(dto.getId());
        xpTask.setReportUserId(xpOperationsUser.getId());
        xpTask.setReportTime(LocalDateTime.now());
@@ -295,38 +298,47 @@
            List<Long> userIds = xpOperationsRoleResult.getData().stream().filter(x -> ids.contains(x.getOperationsUserId()))
                    .map(XpOperationsRole::getOperationsUserId)
                    .distinct().collect(Collectors.toList());
            if (CollUtil.isEmpty(userIds)) {
                throw new ServiceException("未配置车队运维人员");
            }
            //获取首选人的实时定位,计算每个人到事故车辆位置的导航距离
            List<Operations> operationsList = new ArrayList<>();
            for (Long userId : userIds) {
                Operations operations = new Operations();
                operations.setUserId(userId);
                XpOperationsUserPositionDTO vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("id").is(userId)), XpOperationsUserPositionDTO.class);
                if(null != vehiclePosition){
                    LonLatDto start = new LonLatDto(vehiclePosition.getLongitude(), vehiclePosition.getLatitude());
                //获取运维人员实时定位
                XpOperationsUserPositionDTO operationsUserPositionDTO = mongoTemplate.findOne(new Query(Criteria.where("id").is(userId)), XpOperationsUserPositionDTO.class);
                if (null != operationsUserPositionDTO) {
                    LonLatDto start = new LonLatDto(operationsUserPositionDTO.getLongitude(), operationsUserPositionDTO.getLatitude());
                    LonLatDto end = new LonLatDto(xpTask.getVehicleLon().doubleValue(), xpTask.getVehicleLat().doubleValue());
                    //获取导航线路
                    RouteVo routeVo = gdMapGeocodingUtil.getDistanceAndTime(start, end, null, null, null, null);
                    operations.setDistance(routeVo.getDistance());
                    operationsList.add(operations);
                }
                operationsList.add(operations);
            }
            if(operationsList.isEmpty()){
                throw new ServiceException("未找到合适的运维人员");
            }
            //对距离进行排序,去距离最近的人员
            operationsList.sort((o1, o2) -> o1.getDistance().compareTo(o2.getDistance()) * -1);
            Operations operations = operationsList.get(0);
            Long userId = operations.getUserId();
            //如果多人距离相同,可按照上班状态>空闲状态>工号排序
            List<Operations> collect = operationsList.stream().filter(s -> s.getDistance().equals(operations.getDistance())).collect(Collectors.toList());
            if(collect.size() > 1){
            if (collect.size() > 1) {
                //查询已经上班打卡了的人员
                List<XpClockIn> xpClockIns = xpClockInService.list(new QueryWrapper<XpClockIn>().in("app_user_id", collect)
                        .isNull("clock_out_result").last(" and DATE(now()) = DATE(clock_in_time)"));
                if(xpClockIns.size() == 1){
                        .isNull("clock_out_result").last(" and DATE(now()) = DATE(clock_in_time) and clock_out_time is null"));
                if (xpClockIns.size() == 1) {
                    userId = xpClockIns.get(0).getAppUserId();
                }else if(xpClockIns.size() > 1){
                } else if (xpClockIns.size() > 1) {
                    //查询有任务的人员
                    List<Long> collect1 = xpClockIns.stream().map(XpClockIn::getAppUserId).collect(Collectors.toList());
                    List<XpTask> list1 = this.list(new QueryWrapper<XpTask>().eq("task_category", 2).in("handle_user_id", collect1)
                            .in("status", Arrays.asList(0, 1, 4)));
                    if(list1.size() > 0){
                    if (list1.size() > 0) {
                        //对工号进行排序
                        List<String> collect2 = list1.stream().map(XpTask::getHandleUserId).collect(Collectors.toList());
                        //找出没有任务的人员
@@ -348,7 +360,7 @@
        xpTask.setExpiredNoticeSent(0);
        xpTask.setWillTimeoutNoticeSent(0);
        this.save(xpTask);
        if (xpTask.getId() == null && StringUtils.isNotBlank(xpTask.getTaskCode())) {
        if (xpTask.getId() == null && StringUtils.isNotEmpty(xpTask.getTaskCode())) {
            XpTask savedTask = this.getOne(new LambdaQueryWrapper<XpTask>()
                    .eq(XpTask::getTaskCode, xpTask.getTaskCode())
                    .last("limit 1"));
@@ -360,6 +372,90 @@
        // 异步发送消息通知
        String plateNumber = Objects.nonNull(vehicle) ? vehicle.getPlateNumber() : "";
        sendAccidentNotificationAsync(xpTask, plateNumber, taskRule.getProcessingTimeLimit());
        return xpTask;
    }
    @Override
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
    public XpTask saveRemoteDrivingAccident(SaveRemoteDrivingAccidentDto dto) {
        validateRemoteDrivingAccidentDto(dto);
        XpVehicle vehicle = xpVehicleClient.findByVehicleVin(dto.getVin().trim()).getData();
        if (Objects.isNull(vehicle)) {
            throw new ServiceException("上报失败,未获取到车辆信息", I18nKeyConstant.TASK_VEHICLE_NOT_EXIST);
        }
        LocalDateTime reportTime = parseRemoteDrivingTaskTime(dto.getTaskTime());
        Integer taskSource = parseTaskSource(dto.getSource());
        XpTask xpTask = new XpTask();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String code = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5);
        xpTask.setTaskCode(code);
        xpTask.setTaskCategory(2);
        xpTask.setTaskTypeId(normalizeAccidentTaskTypeId(dto.getTaskTypeId()));
        xpTask.setTaskUrgencyLevel(mapRemoteDrivingUrgencyLevel(dto.getTaskUrgencyLevel()));
        xpTask.setTaskDescription(dto.getTaskDescription().trim());
        xpTask.setTaskImage(normalizeTaskImage(dto.getTaskImage()));
        xpTask.setVehicleId(vehicle.getId());
//        xpTask.setVehicleLocation(dto.getVehicleLocation().trim());
//        xpTask.setVehicleLon(dto.getVehicleLon());
//        xpTask.setVehicleLat(dto.getVehicleLat());
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
        if (Objects.isNull(vehiclePosition)) {
            log.error("远程代驾事故上报未获取到车辆当前定位");
            throw new ServiceException("获取车辆实时定位信息失败,请稍后重试", I18nKeyConstant.TASK_SAVE_ERROR);
        }
        xpTask.setVehicleLon(new BigDecimal(vehiclePosition.getPoint().getX()));
        xpTask.setVehicleLat(new BigDecimal(vehiclePosition.getPoint().getY()));
        Map<String, String> geocode = gdMapGeocodingUtil.geocode(xpTask.getVehicleLon().toString(), xpTask.getVehicleLat().toString());
        String address = geocode == null ? null : geocode.get("address");
        if (StringUtils.isBlank(address)) {
            log.error("远程代驾事故上报通过车辆定位从高德获取地址信息失败");
            throw new ServiceException("获取车辆实时定位信息失败,请稍后重试", I18nKeyConstant.TASK_SAVE_ERROR);
        }
        xpTask.setVehicleLocation(address);
        xpTask.setReportUserId(0L);
        xpTask.setReportTime(reportTime);
        xpTask.setStatus(0);
        xpTask.setTaskSource(taskSource);
        xpTask.setCreateBy(dto.getSource().trim());
        XpTaskRule taskRule = xpTaskRuleService.lambdaQuery().last("limit 1").one();
        List<XpTaskRuleRole> list = xpTaskRuleRoleService.lambdaQuery().eq(XpTaskRuleRole::getRuleType, 9).list();
        if (CollUtil.isEmpty(list) || Objects.isNull(taskRule)) {
            throw new ServiceException("未配置车辆事故任务分配规则");
        }
        List<Long> roleIds = list.stream().map(XpTaskRuleRole::getRoleId).collect(Collectors.toList());
        R<List<XpOperationsRole>> xpOperationsRoleResult = xpOperationUserClient.getXpOperationsRoleByRoleIds(roleIds);
        if (CollUtil.isNotEmpty(xpOperationsRoleResult.getData())) {
            Long fleetId = xpFleetVehicleClient.getFleetIdByVehicleId(vehicle.getId()).getData();
            List<Long> ids = xpFleetOperationsClient.getOperationsIdsByFleetId(fleetId).getData();
            // 根据配置的事故处理角色和事故车辆所属车队人员,确定最终的任务分配人列表(取交集)
            List<Long> userIds = xpOperationsRoleResult.getData().stream()
                    .map(XpOperationsRole::getOperationsUserId)
                    .filter(ids::contains)
                    .distinct()
                    .collect(Collectors.toList());
            xpTask.setHandleUserId(StringUtils.join(userIds, ","));
        }
        // 根据事故处理限时配置设置任务截止时间
        xpTask.setEndTime(reportTime.plusMinutes(taskRule.getProcessingTimeLimit()));
        xpTask.setExpiredNoticeSent(0);
        xpTask.setWillTimeoutNoticeSent(0);
        this.save(xpTask);
        if (xpTask.getId() == null && StringUtils.isNotBlank(xpTask.getTaskCode())) {
            XpTask savedTask = this.getOne(new LambdaQueryWrapper<XpTask>()
                    .eq(XpTask::getTaskCode, xpTask.getTaskCode())
                    .last("limit 1"));
            if (savedTask != null && savedTask.getId() != null) {
                xpTask.setId(savedTask.getId());
            }
        }
        sendAccidentNotificationAsync(xpTask, vehicle.getPlateNumber(), taskRule.getProcessingTimeLimit());
        return xpTask;
    }
@@ -377,11 +473,11 @@
    }
    /**
     * 异步发送事故通知
     * @param xpTask 任务信息
     * @param plateNumber 车牌号
     *
     * @param xpTask              任务信息
     * @param plateNumber         车牌号
     * @param processingTimeLimit 处理时限(分钟)
     */
    private void sendAccidentNotificationAsync(XpTask xpTask, String plateNumber, Integer processingTimeLimit) {
@@ -417,9 +513,9 @@
    /**
     * 异步发送事故任务分配通知
     *
     * @param xpTask 任务信息
     * @param handlerUserId 当前分配的处理人
     * @param plateNumber 车牌号
     * @param xpTask              任务信息
     * @param handlerUserId       当前分配的处理人
     * @param plateNumber         车牌号
     * @param processingTimeLimit 处理时限(分钟)
     */
    private void sendAssignedAccidentNotificationAsync(XpTask xpTask, Long handlerUserId, String plateNumber, Integer processingTimeLimit) {
@@ -449,8 +545,8 @@
    /**
     * 构建事故通知文案
     *
     * @param xpTask 任务信息
     * @param plateNumber 车牌号
     * @param xpTask              任务信息
     * @param plateNumber         车牌号
     * @param processingTimeLimit 处理时限(分钟)
     * @return 通知内容
     */
@@ -460,8 +556,9 @@
    /**
     * 构建事故推送 body JSON
     *
     * @param content 消息内容
     * @param xpTask 任务信息
     * @param xpTask  任务信息
     * @return JSON 字符串
     */
    private String buildAccidentPushBodyJson(String content, XpTask xpTask) {
@@ -476,9 +573,9 @@
    /**
     * 保存事故通知记录并发送阿里云推送
     *
     * @param data 接收通知的运维人员
     * @param data    接收通知的运维人员
     * @param content 通知内容
     * @param xpTask 任务信息
     * @param xpTask  任务信息
     */
    private void saveAndPushAccidentNotification(List<XpOperationsUser> data, String content, XpTask xpTask) {
        String bodyJson = buildAccidentPushBodyJson(content, xpTask);
@@ -558,7 +655,8 @@
        res.setPlateNumber(vehicle.getPlateNumber());
        res.setVehicleColor(vehicle.getVehicleColor());
        res.setVehicleCode(vehicle.getVehicleCode());
        res.setVehicleVin(vehicle.getVehicleVin());
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        res.setVehicleVin(vin);
        res.setVehicleLocation(task.getVehicleLocation());
        res.setCreateBy(task.getCreateBy());
        res.setCreateTime(task.getCreateTime());
@@ -648,7 +746,8 @@
        res.setPlateNumber(vehicle.getPlateNumber());
        res.setVehicleColor(vehicle.getVehicleColor());
        res.setVehicleCode(vehicle.getVehicleCode());
        res.setVehicleVin(vehicle.getVehicleVin());
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        res.setVehicleVin(vin);
        res.setVehicleLocation(task.getVehicleLocation());
        res.setCreateBy(task.getCreateBy());
        res.setCreateTime(task.getCreateTime());
@@ -699,7 +798,8 @@
        res.setPlateNumber(vehicle.getPlateNumber());
        res.setVehicleColor(vehicle.getVehicleColor());
        res.setVehicleCode(vehicle.getVehicleCode());
        res.setVehicleVin(vehicle.getVehicleVin());
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        res.setVehicleVin(vin);
        res.setVehicleLocation(task.getVehicleLocation());
        res.setCreateBy(task.getCreateBy());
        res.setCreateTime(task.getCreateTime());
@@ -883,7 +983,8 @@
        res.setPlateNumber(vehicle.getPlateNumber());
        res.setVehicleColor(vehicle.getVehicleColor());
        res.setVehicleCode(vehicle.getVehicleCode());
        res.setVehicleVin(vehicle.getVehicleVin());
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        res.setVehicleVin(vin);
        res.setVehicleLocation(task.getVehicleLocation());
        res.setCreateBy(task.getCreateBy());
        res.setCreateTime(task.getCreateTime());
@@ -1418,6 +1519,92 @@
        return normalizedTypeIds.stream().map(String::valueOf).collect(Collectors.joining(","));
    }
    private void validateRemoteDrivingAccidentDto(SaveRemoteDrivingAccidentDto dto) {
        if (dto == null) {
            throw new ServiceException("请求参数不能为空");
        }
        if (StringUtils.isBlank(dto.getVin())) {
            throw new ServiceException("vin不能为空");
        }
        if (StringUtils.isBlank(dto.getTaskTypeId())) {
            throw new ServiceException("事故类型不能为空");
        }
        if (StringUtils.isBlank(dto.getTaskUrgencyLevel())) {
            throw new ServiceException("事故紧急程度不能为空");
        }
        if (StringUtils.isBlank(dto.getTaskDescription())) {
            throw new ServiceException("事故描述不能为空");
        }
        if (dto.getTaskDescription().trim().length() > 600) {
            throw new ServiceException("事故描述最多600字");
        }
        if (StringUtils.isBlank(dto.getTaskTime())) {
            throw new ServiceException("工单上报时间不能为空");
        }
        if (StringUtils.isBlank(dto.getVehicleLocation())) {
            throw new ServiceException("车辆位置不能为空");
        }
        if (dto.getVehicleLon() == null) {
            throw new ServiceException("车辆经度不能为空");
        }
        if (dto.getVehicleLat() == null) {
            throw new ServiceException("车辆纬度不能为空");
        }
        if (StringUtils.isBlank(dto.getSource())) {
            throw new ServiceException("工单来源不能为空");
        }
    }
    private Integer mapRemoteDrivingUrgencyLevel(String taskUrgencyLevel) {
        String normalized = StringUtils.trimToEmpty(taskUrgencyLevel);
        if (!StringUtils.isNumeric(normalized)) {
            throw new ServiceException("事故紧急程度不支持: " + taskUrgencyLevel);
        }
        Integer urgencyLevel = Integer.valueOf(normalized);
        if (urgencyLevel < 0 || urgencyLevel > 3) {
            throw new ServiceException("事故紧急程度不支持: " + taskUrgencyLevel);
        }
        return urgencyLevel;
    }
    private Integer parseTaskSource(String source) {
        String normalized = StringUtils.trimToEmpty(source);
        if (!StringUtils.isNumeric(normalized)) {
            throw new ServiceException("工单来源不支持: " + source);
        }
        Integer taskSource = Integer.valueOf(normalized);
        if (taskSource < 1 || taskSource > 3) {
            throw new ServiceException("工单来源不支持: " + source);
        }
        return taskSource;
    }
    private LocalDateTime parseRemoteDrivingTaskTime(String taskTime) {
        String normalized = StringUtils.trimToEmpty(taskTime);
        List<DateTimeFormatter> formatters = Arrays.asList(
                DateTimeFormatter.ISO_LOCAL_DATE_TIME,
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
        );
        for (DateTimeFormatter formatter : formatters) {
            try {
                return LocalDateTime.parse(normalized, formatter);
            } catch (Exception ignored) {
            }
        }
        throw new ServiceException("工单上报时间格式不正确: " + taskTime);
    }
    private String normalizeTaskImage(String taskImage) {
        if (StringUtils.isBlank(taskImage)) {
            return "[]";
        }
        String trimmed = taskImage.trim();
        if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
            return trimmed;
        }
        return "[]";
    }
    private List<Long> parseAccidentTaskTypeIds(String taskTypeId) {
        if (StringUtils.isBlank(taskTypeId)) {
            return Collections.emptyList();
@@ -1464,7 +1651,7 @@
        XpTaskRule taskRule = xpTaskRuleService.lambdaQuery().last("limit 1").one();
        int type = 9;
        if(task.getTaskCategory() != 2) {
        if (task.getTaskCategory() != 2) {
            type = Integer.parseInt(task.getTaskTypeId());
        }
@@ -1475,7 +1662,7 @@
        }
        List<XpTask.Reject> rejects = Optional.ofNullable(task.getExcluded()).orElse(new ArrayList<>());
        if(msg != null && Strings.isNotBlank(task.getHandleUserId())) {
        if (msg != null && Strings.isNotBlank(task.getHandleUserId())) {
            XpTask.Reject reject = task.reject(msg);
            rejects.add(reject);
            List<Long> id = Collections.singletonList(Long.parseLong(task.getHandleUserId()));
@@ -1496,19 +1683,19 @@
                .filter(id -> !excludedUserIds.contains(id.toString()))
                .map(String::valueOf).collect(Collectors.joining(","));
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vehicle.getVehicleVin())), VehiclePosition.class);
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
//        VehiclePosition vehiclePosition = new VehiclePosition();
//        vehiclePosition.setPoint(new GeoJsonPoint(103.12615621, 30.264561));
        String handlerUser = chooseNearestAvailableOperationsUser(belongUserIds, vehiclePosition);
        task.setHandleUserId(handlerUser);
        if(handlerUser == null) {
        if (handlerUser == null) {
            task.setStatus(4);
            task.setReassignmentStatus(1);
            noticeAdministrator(task);//TODO 需要通知管理员手动处理,考虑再AliPushUtil 中给管理员发送消息
        }
        updateById(task);
        if(StringUtils.isNotBlank(task.getHandleUserId())){
        if (StringUtils.isNotBlank(task.getHandleUserId())) {
            sendAccidentNotificationAsync(task, vehicle.getPlateNumber(), taskRule.getProcessingTimeLimit());
        }
    }
@@ -1530,7 +1717,8 @@
                .filter(ids::contains)
                .map(String::valueOf).collect(Collectors.joining(","));
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vehicle.getVehicleVin())), VehiclePosition.class);
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
        Map<String, String> geocode = gdMapGeocodingUtil.geocode(vehiclePosition.getPoint().getX() + "", vehiclePosition.getPoint().getY() + "");
        String address = geocode.get("address");
@@ -1548,7 +1736,7 @@
        task.setVehicleLon(new BigDecimal(vehiclePosition.getPoint().getX()));
        String handlerUser = chooseNearestAvailableOperationsUser(belongUserIds, vehiclePosition);
        task.setHandleUserId(handlerUser);
        if(handlerUser == null) {
        if (handlerUser == null) {
            task.setStatus(4);
            task.setReassignmentStatus(1);
            noticeAdministrator(task);
@@ -1564,7 +1752,7 @@
        task.setCreateTime(LocalDateTime.now());
        this.save(task);
        // 异步发送消息通知
         sendAccidentNotificationAsync(task, vehicle.getPlateNumber(), taskRule.getProcessingTimeLimit());
        sendAccidentNotificationAsync(task, vehicle.getPlateNumber(), taskRule.getProcessingTimeLimit());
    }
    @Override
@@ -1574,7 +1762,7 @@
        XpTask task = getById(Long.valueOf(taskId));
        XpVehicle vehicle = xpVehicleClient.queryById(task.getVehicleId()).getData();
        updateTaskStatus(task.getId(), TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE, Long.valueOf(task.getHandleUserId()));
        sendAccidentNotificationAsync(getById(task.getId()), vehicle.getPlateNumber(), (int) Duration.between(LocalDateTime.now(),task.getEndTime()).toMinutes());
        sendAccidentNotificationAsync(getById(task.getId()), vehicle.getPlateNumber(), (int) Duration.between(LocalDateTime.now(), task.getEndTime()).toMinutes());
    }
    @Override
@@ -1674,7 +1862,6 @@
    }
    @Override
    public R assigneeTask(Long id, Long handlerUserId, Long assigneeUserId) {
        XpTask task = this.getById(id);
@@ -1748,12 +1935,12 @@
            task.setTaskSource(2);
            saveTask.add(task);
        }
        for (XpTask task : saveTask) {
            reassign(task.getId(),null);
        }
        this.saveBatch(saveTask);
        for (XpTask task : saveTask) {
            reassign(task.getId(), null);
        }
    }
    @Override
@@ -1773,6 +1960,7 @@
                    I18nKeyConstant.VEHICLE_NOT_EXIST
            );
        }
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        String vehiclePicture = aliOssDownloadUtil.getPictureJSONObject(vehicle.getVehiclePictures());
        if (task.getTaskCategory() == 1) {
            // 常规任务
@@ -1787,7 +1975,7 @@
                    taskManagementDetectionDetailVO.setPlateNumber(vehicle.getPlateNumber());
                    taskManagementDetectionDetailVO.setVehicleColor(vehicle.getVehicleColor());
                    taskManagementDetectionDetailVO.setVehicleCode(vehicle.getVehicleCode());
                    taskManagementDetectionDetailVO.setVehicleVin(vehicle.getVehicleVin());
                    taskManagementDetectionDetailVO.setVehicleVin(vin);
                    taskManagementDetectionDetailVO.setVehicleLocation(task.getVehicleLocation());
                    taskManagementDetectionDetailVO.setVehiclePictures(vehiclePicture);
@@ -1934,7 +2122,7 @@
                    taskManagementChargingDetailVO.setPlateNumber(vehicle.getPlateNumber());
                    taskManagementChargingDetailVO.setVehicleColor(vehicle.getVehicleColor());
                    taskManagementChargingDetailVO.setVehicleCode(vehicle.getVehicleCode());
                    taskManagementChargingDetailVO.setVehicleVin(vehicle.getVehicleVin());
                    taskManagementChargingDetailVO.setVehicleVin(vin);
                    taskManagementChargingDetailVO.setVehicleLocation(task.getVehicleLocation());
                    taskManagementChargingDetailVO.setTaskCode(task.getTaskCode());
                    taskManagementChargingDetailVO.setVehiclePictures(vehiclePicture);
@@ -1975,7 +2163,7 @@
                    taskManagementPreparationDetailVO.setPlateNumber(vehicle.getPlateNumber());
                    taskManagementPreparationDetailVO.setVehicleColor(vehicle.getVehicleColor());
                    taskManagementPreparationDetailVO.setVehicleCode(vehicle.getVehicleCode());
                    taskManagementPreparationDetailVO.setVehicleVin(vehicle.getVehicleVin());
                    taskManagementPreparationDetailVO.setVehicleVin(vin);
                    taskManagementPreparationDetailVO.setVehicleLocation(task.getVehicleLocation());
                    taskManagementPreparationDetailVO.setTaskCode(task.getTaskCode());
                    taskManagementPreparationDetailVO.setVehiclePictures(vehiclePicture);
@@ -2016,7 +2204,7 @@
                    taskManagementCleanDetailVO.setPlateNumber(vehicle.getPlateNumber());
                    taskManagementCleanDetailVO.setVehicleColor(vehicle.getVehicleColor());
                    taskManagementCleanDetailVO.setVehicleCode(vehicle.getVehicleCode());
                    taskManagementCleanDetailVO.setVehicleVin(vehicle.getVehicleVin());
                    taskManagementCleanDetailVO.setVehicleVin(vin);
                    taskManagementCleanDetailVO.setVehicleLocation(task.getVehicleLocation());
                    taskManagementCleanDetailVO.setTaskCode(task.getTaskCode());
                    taskManagementCleanDetailVO.setVehiclePictures(vehiclePicture);
@@ -2045,7 +2233,7 @@
                    taskManagementRepairDetailVO.setPlateNumber(vehicle.getPlateNumber());
                    taskManagementRepairDetailVO.setVehicleColor(vehicle.getVehicleColor());
                    taskManagementRepairDetailVO.setVehicleCode(vehicle.getVehicleCode());
                    taskManagementRepairDetailVO.setVehicleVin(vehicle.getVehicleVin());
                    taskManagementRepairDetailVO.setVehicleVin(vin);
                    taskManagementRepairDetailVO.setVehicleLocation(task.getVehicleLocation());
                    taskManagementRepairDetailVO.setTaskCode(task.getTaskCode());
                    taskManagementRepairDetailVO.setVehiclePictures(vehiclePicture);
@@ -2088,7 +2276,7 @@
                    res.setVehicleColor(vehicle.getVehicleColor());
                    res.setVehicleCode(vehicle.getVehicleCode());
                    res.setVehicleLocation(task.getVehicleLocation());
                    res.setVehicleVin(vehicle.getVehicleVin());
                    res.setVehicleVin(vin);
                    res.setTaskCode(task.getTaskCode());
                    res.setVehiclePictures(vehiclePicture);
                    XpTaskHandleDetailRoutine xpTaskHandleDetailRoutine = xpTaskHandleDetailRoutineMapper.selectOne(new LambdaQueryWrapper<XpTaskHandleDetailRoutine>()
@@ -2111,7 +2299,7 @@
                    res.setVehicleColor(vehicle.getVehicleColor());
                    res.setVehicleCode(vehicle.getVehicleCode());
                    res.setVehicleLocation(task.getVehicleLocation());
                    res.setVehicleVin(vehicle.getVehicleVin());
                    res.setVehicleVin(vin);
                    managementDetailVO.setRoutineDetailVO(res);
                    break;
@@ -2160,7 +2348,6 @@
                }
                res.setTaskImage(JSONArray.toJSONString(jsonArray));
            }
            res.setId(id);
            res.setVehicleId(vehicle.getId());
            res.setTaskUrgencyLevel(task.getTaskUrgencyLevel());
@@ -2168,7 +2355,7 @@
            res.setVehicleColor(vehicle.getVehicleColor());
            res.setVehicleCode(vehicle.getVehicleCode());
            res.setVehicleLocation(task.getVehicleLocation());
            res.setVehicleVin(vehicle.getVehicleVin());
            res.setVehicleVin(vin);
            if (task.getReportUserId().equals(0L)) {
                // 系统补偿上传车辆异常任务 为系统创建
                res.setReportUserId(0L);
@@ -2230,15 +2417,16 @@
    /**
     * 任务改派操作
     *
     * @param vo
     */
    @Override
    public void taskReassignment(TaskReassignmentVo vo) {
        XpTask xpTask = this.getById(vo.getTaskId());
        if(null == xpTask){
        if (null == xpTask) {
            throw new ServiceException("无效的任务", I18nKeyConstant.TASK_NOT_EXIST);
        }
        if(2 == xpTask.getReassignmentStatus()){
        if (2 == xpTask.getReassignmentStatus()) {
            throw new ServiceException("任务已改派,不能重复操作", I18nKeyConstant.TASK_HAS_BEEN_REASSIGNED);
        }
        xpTask.setReassignmentStatus(2);