From da6a14067bbb3e98d8a1a41c6d7d9883b09e5fee Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期四, 26 二月 2026 21:50:28 +0800
Subject: [PATCH] Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi

---
 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpCruisePlanServiceImpl.java |  319 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 315 insertions(+), 4 deletions(-)

diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpCruisePlanServiceImpl.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpCruisePlanServiceImpl.java
index 0842f42..e5c6969 100644
--- a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpCruisePlanServiceImpl.java
+++ b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpCruisePlanServiceImpl.java
@@ -2,24 +2,39 @@
 
 import cn.hutool.core.collection.CollUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+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.operation.XpCruisePlan;
 import com.xiaopeng.api.model.operation.XpCruisePlanPoint;
 import com.xiaopeng.api.model.operation.XpCruisePlanVehicle;
+import com.xiaopeng.api.model.operation.XpPoint;
+import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
+import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
+import com.xiaopeng.common.core.domain.R;
+import com.xiaopeng.common.core.exception.ServiceException;
 import com.xiaopeng.common.core.web.page.PageInfo;
+import com.xiaopeng.common.security.utils.SecurityUtils;
+import com.xiaopeng.operation.constant.I18nKeyConstant;
+import com.xiaopeng.operation.dto.XpCruisePlanAddDTO;
+import com.xiaopeng.operation.dto.XpCruisePlanEditDTO;
 import com.xiaopeng.operation.mapper.XpCruisePlanMapper;
 import com.xiaopeng.operation.query.CruisePlanQuery;
 import com.xiaopeng.operation.service.IXpCruisePlanPointService;
 import com.xiaopeng.operation.service.IXpCruisePlanService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.xiaopeng.operation.service.IXpCruisePlanVehicleService;
+import com.xiaopeng.operation.service.IXpPointService;
+import com.xiaopeng.operation.vo.XpCruisePlanDetailVO;
+import com.xiaopeng.operation.vo.XpCruisePlanPointVO;
+import com.xiaopeng.operation.vo.XpCruisePlanVehicleVO;
 import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -36,7 +51,10 @@
 
     private final IXpCruisePlanPointService xpCruisePlanPointService;
     private final IXpCruisePlanVehicleService xpCruisePlanVehicleService;
-
+    private final IXpPointService xpPointService;
+    private final XpVehicleClient xpVehicleClient;
+    private final XpFleetVehicleClient xpFleetVehicleClient;
+    private final XpFleetClient xpFleetClient;
     @Override
     public PageInfo<XpCruisePlan> getPageList(CruisePlanQuery query) {
         PageInfo<XpCruisePlan> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
@@ -59,4 +77,297 @@
         pageInfo.setRecords(page.getRecords());
         return pageInfo;
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void add(XpCruisePlanAddDTO dto) {
+        //1.校验巡游计划名称
+        validatePlanName(dto.getPlanName(), null);
+        //2.校验点位参数
+        validatePointList(dto.getPointList());
+        Set<Long> vehicleIdSet = validateVehicleList(dto.getVehicleIdList());
+        //3.校验车辆是否已绑定其他巡游计划
+        validateVehicleBind(vehicleIdSet, null);
+        XpCruisePlan plan = new XpCruisePlan();
+        plan.setPlanName(dto.getPlanName());
+        plan.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
+        boolean planSaved = save(plan);
+        if (!planSaved || plan.getId() == null) {
+            throw new ServiceException("新增巡游计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL);
+        }
+        List<XpCruisePlanPoint> pointList = buildPointList(plan.getId(), dto.getPointList());
+        boolean pointSaved = xpCruisePlanPointService.saveBatch(pointList);
+        if (!pointSaved) {
+            throw new ServiceException("新增巡游计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL);
+        }
+        List<XpCruisePlanVehicle> vehicleList = buildVehicleList(plan.getId(), dto.getVehicleIdList());
+        boolean vehicleSaved = xpCruisePlanVehicleService.saveBatch(vehicleList);
+        if (!vehicleSaved) {
+            throw new ServiceException("新增巡游计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void edit(XpCruisePlanEditDTO dto) {
+        if (dto.getId() == null) {
+            throw new ServiceException("巡游计划ID不能为空", I18nKeyConstant.CRUISE_PLAN_ID_EMPTY);
+        }
+        XpCruisePlan plan = getById(dto.getId());
+        if (plan == null) {
+            throw new ServiceException("巡游计划不存在", I18nKeyConstant.CRUISE_PLAN_NOT_EXIST);
+        }
+        validatePlanName(dto.getPlanName(), dto.getId());
+        validatePointList(dto.getPointList());
+        Set<Long> vehicleIdSet = validateVehicleList(dto.getVehicleIdList());
+        validateVehicleBind(vehicleIdSet, dto.getId());
+        plan.setPlanName(dto.getPlanName());
+        plan.setUpdateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
+        boolean planUpdated = updateById(plan);
+        if (!planUpdated) {
+            throw new ServiceException("编辑巡游计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL);
+        }
+        xpCruisePlanPointService.lambdaUpdate()
+                .eq(XpCruisePlanPoint::getCruisePlanId, dto.getId())
+                .remove();
+        xpCruisePlanVehicleService.lambdaUpdate()
+                .eq(XpCruisePlanVehicle::getCruisePlanId, dto.getId())
+                .remove();
+        List<XpCruisePlanPoint> pointList = buildPointList(dto.getId(), dto.getPointList());
+        boolean pointSaved = xpCruisePlanPointService.saveBatch(pointList);
+        if (!pointSaved) {
+            throw new ServiceException("编辑巡游计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL);
+        }
+        List<XpCruisePlanVehicle> vehicleList = buildVehicleList(dto.getId(), dto.getVehicleIdList());
+        boolean vehicleSaved = xpCruisePlanVehicleService.saveBatch(vehicleList);
+        if (!vehicleSaved) {
+            throw new ServiceException("编辑巡游计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteById(Long id) {
+        xpCruisePlanPointService.lambdaUpdate()
+                .eq(XpCruisePlanPoint::getCruisePlanId, id)
+                .remove();
+        xpCruisePlanVehicleService.lambdaUpdate()
+                .eq(XpCruisePlanVehicle::getCruisePlanId, id)
+                .remove();
+        removeById(id);
+    }
+
+    @Override
+    public XpCruisePlanDetailVO detail(Long id) {
+        if (id == null) {
+            throw new ServiceException("巡游计划ID不能为空", I18nKeyConstant.CRUISE_PLAN_ID_EMPTY);
+        }
+        XpCruisePlan plan = getById(id);
+        if (plan == null) {
+            throw new ServiceException("巡游计划不存在", I18nKeyConstant.CRUISE_PLAN_NOT_EXIST);
+        }
+        List<XpCruisePlanPoint> planPoints = xpCruisePlanPointService.lambdaQuery()
+                .eq(XpCruisePlanPoint::getCruisePlanId, id)
+                .orderByAsc(XpCruisePlanPoint::getSortOrder)
+                .list();
+        List<Long> pointIds = planPoints.stream()
+                .map(XpCruisePlanPoint::getPointId)
+                .filter(Objects::nonNull)
+                .map(Integer::longValue)
+                .collect(Collectors.toList());
+        Map<Long, XpPoint> pointMap = CollUtil.isNotEmpty(pointIds)
+                ? xpPointService.listByIds(pointIds).stream()
+                .collect(Collectors.toMap(XpPoint::getId, v -> v))
+                : Collections.emptyMap();
+        List<XpCruisePlanPointVO> pointList = planPoints.stream().map(planPoint -> {
+            XpCruisePlanPointVO vo = new XpCruisePlanPointVO();
+            vo.setPointId(planPoint.getPointId());
+            vo.setSortOrder(planPoint.getSortOrder());
+            XpPoint point = pointMap.get(planPoint.getPointId() == null ? null : planPoint.getPointId().longValue());
+            if (point != null) {
+                vo.setPointName(point.getPointName());
+                vo.setPointAddress(point.getPointAddress());
+            }
+            return vo;
+        }).collect(Collectors.toList());
+
+        List<XpCruisePlanVehicle> planVehicles = xpCruisePlanVehicleService.lambdaQuery()
+                .eq(XpCruisePlanVehicle::getCruisePlanId, id)
+                .list();
+        List<Long> vehicleIds = planVehicles.stream()
+                .map(XpCruisePlanVehicle::getVehicleId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+        Map<Long, XpVehicle> vehicleMap;
+        if (CollUtil.isNotEmpty(vehicleIds)) {
+            R<List<XpVehicle>> vehicleResult = xpVehicleClient.listByIds(vehicleIds);
+            if (vehicleResult != null && CollUtil.isNotEmpty(vehicleResult.getData())) {
+                vehicleMap = vehicleResult.getData().stream()
+                        .collect(Collectors.toMap(XpVehicle::getId, v -> v));
+            } else {
+                vehicleMap = Collections.emptyMap();
+            }
+        } else {
+            vehicleMap = Collections.emptyMap();
+        }
+        Map<Long, Long> vehicleFleetIdMap = new HashMap<>();
+        if (CollUtil.isNotEmpty(vehicleIds)) {
+            for (Long vehicleId : vehicleIds) {
+                R<Long> fleetIdResult = xpFleetVehicleClient.getFleetIdByVehicleId(vehicleId);
+                if (fleetIdResult != null && fleetIdResult.getData() != null) {
+                    vehicleFleetIdMap.put(vehicleId, fleetIdResult.getData());
+                }
+            }
+        }
+        Map<Long, String> fleetNameMap;
+        if (!vehicleFleetIdMap.isEmpty()) {
+            List<Long> fleetIds = vehicleFleetIdMap.values().stream().distinct().collect(Collectors.toList());
+            R<List<XpFleet>> fleetResult = xpFleetClient.listByIds(fleetIds);
+            if (fleetResult != null && CollUtil.isNotEmpty(fleetResult.getData())) {
+                fleetNameMap = fleetResult.getData().stream()
+                        .collect(Collectors.toMap(XpFleet::getId, XpFleet::getFleetName, (a, b) -> a));
+            } else {
+                fleetNameMap = Collections.emptyMap();
+            }
+        } else {
+            fleetNameMap = Collections.emptyMap();
+        }
+        List<XpCruisePlanVehicleVO> vehicleList = planVehicles.stream().map(planVehicle -> {
+            XpCruisePlanVehicleVO vo = new XpCruisePlanVehicleVO();
+            vo.setVehicleId(planVehicle.getVehicleId());
+            XpVehicle vehicle = vehicleMap.get(planVehicle.getVehicleId());
+            if (vehicle != null) {
+                vo.setVehicleCode(vehicle.getVehicleCode());
+                vo.setPlateNumber(vehicle.getPlateNumber());
+                vo.setVehicleModel(vehicle.getVehicleModel());
+            }
+            Long fleetId = vehicleFleetIdMap.get(planVehicle.getVehicleId());
+            if (fleetId != null) {
+                vo.setFleetName(fleetNameMap.get(fleetId));
+            }
+            return vo;
+        }).collect(Collectors.toList());
+
+        XpCruisePlanDetailVO detailVO = new XpCruisePlanDetailVO();
+        detailVO.setId(plan.getId());
+        detailVO.setPlanName(plan.getPlanName());
+        detailVO.setPointNum(planPoints.size());
+        detailVO.setVehicleNum(planVehicles.size());
+        detailVO.setCreateTime(plan.getCreateTime());
+        detailVO.setPointList(pointList);
+        detailVO.setVehicleList(vehicleList);
+        return detailVO;
+    }
+
+    /**
+     * 校验巡游计划名称
+     * @param planName
+     * @param excludePlanId
+     */
+    private void validatePlanName(String planName, Long excludePlanId) {
+        if (StringUtils.isBlank(planName)) {
+            throw new ServiceException("计划名称不能为空", I18nKeyConstant.CRUISE_PLAN_NAME_EMPTY);
+        }
+        Long count = lambdaQuery()
+                .eq(XpCruisePlan::getPlanName, planName)
+                .ne(excludePlanId != null, XpCruisePlan::getId, excludePlanId)
+                .count();
+        if (count > 0) {
+            throw new ServiceException("计划名称已存在", I18nKeyConstant.CRUISE_PLAN_NAME_EXISTS);
+        }
+    }
+
+    /**
+     * 校验关联点位列表
+     * @param pointList
+     */
+    private void validatePointList(List<XpCruisePlanAddDTO.CruisePlanPointDTO> pointList) {
+        if (CollUtil.isEmpty(pointList)) {
+            throw new ServiceException("关联点位列表不能为空", I18nKeyConstant.CRUISE_PLAN_POINT_EMPTY);
+        }
+        Set<Integer> pointIdSet = new HashSet<>();
+        for (XpCruisePlanAddDTO.CruisePlanPointDTO pointDTO : pointList) {
+            if (pointDTO.getPointId() == null || pointDTO.getSortOrder() == null || pointDTO.getStopFlag() == null) {
+                throw new ServiceException("点位参数不完整", I18nKeyConstant.CRUISE_PLAN_POINT_INCOMPLETE);
+            }
+            if (pointDTO.getStopFlag() != 0 && pointDTO.getStopFlag() != 1) {
+                throw new ServiceException("点位停车标识不合法", I18nKeyConstant.CRUISE_PLAN_STOP_FLAG_INVALID);
+            }
+            if (!pointIdSet.add(pointDTO.getPointId())) {
+                throw new ServiceException("点位ID重复", I18nKeyConstant.CRUISE_PLAN_POINT_DUPLICATE);
+            }
+        }
+    }
+
+    /**
+     * 校验关联车辆列表
+     * @param vehicleIdList
+     * @return
+     */
+    private Set<Long> validateVehicleList(List<Long> vehicleIdList) {
+        if (CollUtil.isEmpty(vehicleIdList)) {
+            throw new ServiceException("关联车辆列表不能为空", I18nKeyConstant.CRUISE_PLAN_VEHICLE_EMPTY);
+        }
+        Set<Long> vehicleIdSet = new HashSet<>();
+        for (Long vehicleId : vehicleIdList) {
+            if (vehicleId == null) {
+                throw new ServiceException("车辆参数不完整", I18nKeyConstant.CRUISE_PLAN_VEHICLE_INCOMPLETE);
+            }
+            if (!vehicleIdSet.add(vehicleId)) {
+                throw new ServiceException("车辆ID重复", I18nKeyConstant.CRUISE_PLAN_VEHICLE_DUPLICATE);
+            }
+        }
+        return vehicleIdSet;
+    }
+
+    /**
+     * 校验车辆是否已绑定其他巡游计划
+     * @param vehicleIdSet
+     * @param excludePlanId
+     */
+    private void validateVehicleBind(Set<Long> vehicleIdSet, Long excludePlanId) {
+        List<XpCruisePlanVehicle> boundVehicles = xpCruisePlanVehicleService.lambdaQuery()
+                .in(XpCruisePlanVehicle::getVehicleId, vehicleIdSet)
+                .ne(excludePlanId != null, XpCruisePlanVehicle::getCruisePlanId, excludePlanId)
+                .list();
+        if (CollUtil.isNotEmpty(boundVehicles)) {
+            throw new ServiceException("车辆已关联其他巡游计划", I18nKeyConstant.CRUISE_PLAN_VEHICLE_ALREADY_BOUND);
+        }
+    }
+
+    /**
+     * 构建巡游计划点位列表
+     * @param planId
+     * @param pointList
+     * @return
+     */
+    private List<XpCruisePlanPoint> buildPointList(Long planId, List<XpCruisePlanAddDTO.CruisePlanPointDTO> pointList) {
+        List<XpCruisePlanPoint> result = new ArrayList<>(pointList.size());
+        for (XpCruisePlanAddDTO.CruisePlanPointDTO pointDTO : pointList) {
+            XpCruisePlanPoint point = new XpCruisePlanPoint();
+            point.setCruisePlanId(planId);
+            point.setPointId(pointDTO.getPointId());
+            point.setSortOrder(pointDTO.getSortOrder());
+            point.setStopFlag(pointDTO.getStopFlag());
+            result.add(point);
+        }
+        return result;
+    }
+
+    /**
+     * 构建巡游计划车辆列表
+     * @param planId
+     * @param vehicleIdList
+     * @return
+     */
+    private List<XpCruisePlanVehicle> buildVehicleList(Long planId, List<Long> vehicleIdList) {
+        List<XpCruisePlanVehicle> result = new ArrayList<>(vehicleIdList.size());
+        for (Long vehicleId : vehicleIdList) {
+            XpCruisePlanVehicle vehicle = new XpCruisePlanVehicle();
+            vehicle.setCruisePlanId(planId);
+            vehicle.setVehicleId(vehicleId);
+            result.add(vehicle);
+        }
+        return result;
+    }
 }

--
Gitblit v1.7.1