package com.xiaopeng.operation.service.impl; import cn.hutool.core.collection.CollUtil; 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.feignClient.operation.XpTestPointClient; import com.xiaopeng.api.feignClient.order.XpTestOrderClient; 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.map.XpTestPoint; import com.xiaopeng.api.model.operation.XpTestPlanPoint; import com.xiaopeng.api.model.operation.XpTestPlanVehicle; import com.xiaopeng.api.model.operation.XpTestPlan; import com.xiaopeng.api.model.order.XpTestOrder; import com.xiaopeng.api.model.vehicleConvoy.XpFleet; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.map.QueryTestPoint; 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.operation.constant.I18nKeyConstant; import com.xiaopeng.operation.dto.XpTestPlanAddDTO; import com.xiaopeng.operation.dto.XpTestPlanEditDTO; import com.xiaopeng.operation.mapper.XpTestPlanMapper; import com.xiaopeng.operation.query.TestPlanQuery; import com.xiaopeng.operation.service.*; import com.xiaopeng.operation.vo.*; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType; import org.apache.shardingsphere.transaction.core.TransactionType; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.stream.Collectors; /** *

* 测试计划 服务实现类 *

* * @author mitao * @since 2026-02-26 */ @Service @RequiredArgsConstructor public class XpTestPlanServiceImpl extends ServiceImpl implements IXpTestPlanService { private final IXpTestPlanPointService xpTestPlanPointService; private final IXpTestPlanVehicleService xpTestPlanVehicleService; private final XpTestPointClient testPointClient; private final XpVehicleClient xpVehicleClient; private final XpFleetVehicleClient xpFleetVehicleClient; private final XpFleetClient xpFleetClient; private final XpTestOrderClient xpTestOrderClient; @Override public PageInfo getPageList(TestPlanQuery query) { PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); Page page = lambdaQuery() .like(StringUtils.isNotBlank(query.getPlanName()), XpTestPlan::getPlanName, query.getPlanName()) .orderByDesc(XpTestPlan::getCreateTime) .page(pageInfo); //收集测试计划ID List planIds = page.getRecords().stream().map(XpTestPlan::getId).collect(Collectors.toList()); // 批量查询测试计划点位和车辆信息,并组装到测试计划对象中 Map> pointMap = CollUtil.isNotEmpty(planIds) ? xpTestPlanPointService.lambdaQuery().in(XpTestPlanPoint::getTestPlanId, planIds) .list().stream().collect(Collectors.groupingBy(XpTestPlanPoint::getTestPlanId)) : Collections.emptyMap(); Map> vehicleMap = CollUtil.isNotEmpty(planIds) ? xpTestPlanVehicleService.lambdaQuery().in(XpTestPlanVehicle::getTestPlanId, planIds) .list().stream().collect(Collectors.groupingBy(XpTestPlanVehicle::getTestPlanId)) : Collections.emptyMap(); page.getRecords().forEach(plan -> { if(pointMap.size() > 0){ plan.setPointNum(null == pointMap.get(plan.getId()) ? 0 : pointMap.get(plan.getId()).size()); }else{ plan.setPointNum(0); } if(vehicleMap.size() > 0){ plan.setVehicleNum(null == vehicleMap.get(plan.getId()) ? 0 : vehicleMap.get(plan.getId()).size()); }else{ plan.setVehicleNum(0); } Long testOrder = xpTestOrderClient.queryCountByTestPlanId(plan.getId()).getData(); plan.setOrderNum(testOrder.intValue()); }); pageInfo.setRecords(page.getRecords()); return pageInfo; } @Override @Transactional @ShardingSphereTransactionType(TransactionType.BASE) public void add(XpTestPlanAddDTO dto) { //1.校验测试计划名称 validatePlanName(dto.getPlanName(), null); //2.校验点位参数 validatePointList(dto.getPointList()); Set vehicleIdSet = validateVehicleList(dto.getVehicleIdList()); //3.校验车辆是否已绑定其他测试计划 validateVehicleBind(vehicleIdSet, null); XpTestPlan plan = new XpTestPlan(); plan.setPlanName(dto.getPlanName()); boolean planSaved = save(plan); if (!planSaved || plan.getId() == null) { throw new ServiceException("新增测试计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL); } List pointList = buildPointList(plan.getId(), dto.getPointList()); boolean pointSaved = xpTestPlanPointService.saveBatch(pointList); if (!pointSaved) { throw new ServiceException("新增测试计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL); } List vehicleList = buildVehicleList(plan.getId(), dto.getVehicleIdList()); boolean vehicleSaved = xpTestPlanVehicleService.saveBatch(vehicleList); if (!vehicleSaved) { throw new ServiceException("新增测试计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL); } } @Override @Transactional @ShardingSphereTransactionType(TransactionType.BASE) public void edit(XpTestPlanEditDTO dto) { if (dto.getId() == null) { throw new ServiceException("测试计划ID不能为空", I18nKeyConstant.CRUISE_PLAN_ID_EMPTY); } XpTestPlan plan = getById(dto.getId()); if (plan == null) { throw new ServiceException("测试计划不存在", I18nKeyConstant.CRUISE_PLAN_NOT_EXIST); } validatePlanName(dto.getPlanName(), dto.getId()); validatePointList(dto.getPointList()); Set vehicleIdSet = validateVehicleList(dto.getVehicleIdList()); validateVehicleBind(vehicleIdSet, dto.getId()); plan.setPlanName(dto.getPlanName()); boolean planUpdated = updateById(plan); if (!planUpdated) { throw new ServiceException("编辑测试计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL); } xpTestPlanPointService.lambdaUpdate() .eq(XpTestPlanPoint::getTestPlanId, dto.getId()) .remove(); xpTestPlanVehicleService.lambdaUpdate() .eq(XpTestPlanVehicle::getTestPlanId, dto.getId()) .remove(); List pointList = buildPointList(dto.getId(), dto.getPointList()); boolean pointSaved = xpTestPlanPointService.saveBatch(pointList); if (!pointSaved) { throw new ServiceException("编辑测试计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL); } List vehicleList = buildVehicleList(dto.getId(), dto.getVehicleIdList()); boolean vehicleSaved = xpTestPlanVehicleService.saveBatch(vehicleList); if (!vehicleSaved) { throw new ServiceException("编辑测试计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL); } } @Override @Transactional @ShardingSphereTransactionType(TransactionType.BASE) public void deleteById(Long id) { xpTestPlanPointService.lambdaUpdate() .eq(XpTestPlanPoint::getTestPlanId, id) .remove(); xpTestPlanVehicleService.lambdaUpdate() .eq(XpTestPlanVehicle::getTestPlanId, id) .remove(); removeById(id); } @Override public XpTestPlanDetailVO detail(Long id) { if (id == null) { throw new ServiceException("测试计划ID不能为空", I18nKeyConstant.CRUISE_PLAN_ID_EMPTY); } XpTestPlan plan = getById(id); if (plan == null) { throw new ServiceException("测试计划不存在", I18nKeyConstant.CRUISE_PLAN_NOT_EXIST); } List planPoints = xpTestPlanPointService.lambdaQuery() .eq(XpTestPlanPoint::getTestPlanId, id) .list(); List pointIds = planPoints.stream() .map(XpTestPlanPoint::getStartTestPointId) .filter(Objects::nonNull) .collect(Collectors.toList()); List pointIds1 = planPoints.stream() .map(XpTestPlanPoint::getEndTestPointId) .filter(Objects::nonNull) .collect(Collectors.toList()); pointIds.addAll(pointIds1); QueryTestPoint query = new QueryTestPoint(); query.setIds(pointIds); List data = testPointClient.queryPointByIds(query).getData(); Map pointMap = CollUtil.isNotEmpty(pointIds) ? data.stream() .collect(Collectors.toMap(XpTestPoint::getId, v -> v)) : Collections.emptyMap(); List pointList = planPoints.stream().map(planPoint -> { XpTestPlanPointVO vo = new XpTestPlanPointVO(); vo.setStartTestPointId(planPoint.getStartTestPointId()); vo.setEndTestPointId(planPoint.getEndTestPointId()); vo.setStopFlag(planPoint.getStopFlag()); vo.setTestOrderType(planPoint.getTestOrderType()); XpTestPoint point = pointMap.get(planPoint.getStartTestPointId() == null ? null : planPoint.getStartTestPointId().longValue()); if (point != null) { vo.setStartTestPointName(point.getPointName()); vo.setStartTestPointAddress(point.getPointAddress()); } XpTestPoint point1 = pointMap.get(planPoint.getEndTestPointId() == null ? null : planPoint.getEndTestPointId().longValue()); if (point != null) { vo.setEndTestPointName(point1.getPointName()); vo.setEndTestPointAddress(point1.getPointAddress()); } vo.setStopFlag(planPoint.getStopFlag()); return vo; }).collect(Collectors.toList()); List planVehicles = xpTestPlanVehicleService.lambdaQuery() .eq(XpTestPlanVehicle::getTestPlanId, id) .list(); List vehicleIds = planVehicles.stream() .map(XpTestPlanVehicle::getVehicleId) .filter(Objects::nonNull) .collect(Collectors.toList()); Map vehicleMap; if (CollUtil.isNotEmpty(vehicleIds)) { R> 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 vehicleFleetIdMap = new HashMap<>(); if (CollUtil.isNotEmpty(vehicleIds)) { for (Long vehicleId : vehicleIds) { R fleetIdResult = xpFleetVehicleClient.getFleetIdByVehicleId(vehicleId); if (fleetIdResult != null && fleetIdResult.getData() != null) { vehicleFleetIdMap.put(vehicleId, fleetIdResult.getData()); } } } Map fleetNameMap; if (!vehicleFleetIdMap.isEmpty()) { List fleetIds = vehicleFleetIdMap.values().stream().distinct().collect(Collectors.toList()); R> 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 vehicleList = planVehicles.stream().map(planVehicle -> { XpTestPlanVehicleVO vo = new XpTestPlanVehicleVO(); vo.setVehicleId(planVehicle.getVehicleId()); XpVehicle vehicle = vehicleMap.get(planVehicle.getVehicleId()); if (vehicle != null) { vo.setVehicleCode(vehicle.getVehicleCode()); vo.setPlateNumber(vehicle.getPlateNumber()); vo.setVehicleModel(vehicle.getVehicleModelName()); } Long fleetId = vehicleFleetIdMap.get(planVehicle.getVehicleId()); if (fleetId != null) { vo.setFleetName(fleetNameMap.get(fleetId)); } return vo; }).collect(Collectors.toList()); XpTestPlanDetailVO detailVO = new XpTestPlanDetailVO(); 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(XpTestPlan::getPlanName, planName) .ne(excludePlanId != null, XpTestPlan::getId, excludePlanId) .count(); if (count > 0) { throw new ServiceException("计划名称已存在", I18nKeyConstant.CRUISE_PLAN_NAME_EXISTS); } } /** * 校验关联点位列表 * @param pointList */ private void validatePointList(List pointList) { if (CollUtil.isEmpty(pointList)) { throw new ServiceException("关联点位列表不能为空", I18nKeyConstant.CRUISE_PLAN_POINT_EMPTY); } Set pointIdSet = new HashSet<>(); for (XpTestPlanAddDTO.TestPlanPointDTO pointDTO : pointList) { if (pointDTO.getStartTestPointId() == null || pointDTO.getEndTestPointId() == null) { throw new ServiceException("点位参数不完整", I18nKeyConstant.CRUISE_PLAN_POINT_INCOMPLETE); } if (!pointIdSet.add(pointDTO.getStartTestPointId()) || !pointIdSet.add(pointDTO.getEndTestPointId())) { throw new ServiceException("点位ID重复", I18nKeyConstant.CRUISE_PLAN_POINT_DUPLICATE); } } } /** * 校验关联车辆列表 * @param vehicleIdList * @return */ private Set validateVehicleList(List vehicleIdList) { if (CollUtil.isEmpty(vehicleIdList)) { throw new ServiceException("关联车辆列表不能为空", I18nKeyConstant.CRUISE_PLAN_VEHICLE_EMPTY); } Set 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 vehicleIdSet, Long excludePlanId) { List boundVehicles = xpTestPlanVehicleService.lambdaQuery() .in(XpTestPlanVehicle::getVehicleId, vehicleIdSet) .ne(excludePlanId != null, XpTestPlanVehicle::getTestPlanId, excludePlanId) .list(); if (CollUtil.isNotEmpty(boundVehicles)) { List data = xpVehicleClient.listByIds(boundVehicles.stream().map(XpTestPlanVehicle::getVehicleId).collect(Collectors.toList())).getData(); if (CollUtil.isNotEmpty(data)) { String plateNumbers = data.stream().map(XpVehicle::getPlateNumber).collect(Collectors.joining(",")); Object[] args = Lists.newArrayList(plateNumbers).toArray(); throw new ServiceException("车辆已关联其他测试计划", I18nKeyConstant.CRUISE_PLAN_VEHICLE_ALREADY_BOUND, args); } } } /** * 构建测试计划点位列表 * @param planId * @param pointList * @return */ private List buildPointList(Long planId, List pointList) { List result = new ArrayList<>(pointList.size()); for (XpTestPlanAddDTO.TestPlanPointDTO pointDTO : pointList) { XpTestPlanPoint point = new XpTestPlanPoint(); point.setTestPlanId(planId); point.setStartTestPointId(pointDTO.getStartTestPointId()); point.setEndTestPointId(pointDTO.getEndTestPointId()); point.setStopFlag(pointDTO.getStopFlag()); point.setTestOrderType(pointDTO.getTestOrderType()); result.add(point); } return result; } /** * 构建测试计划车辆列表 * @param planId * @param vehicleIdList * @return */ private List buildVehicleList(Long planId, List vehicleIdList) { List result = new ArrayList<>(vehicleIdList.size()); for (Long vehicleId : vehicleIdList) { XpTestPlanVehicle vehicle = new XpTestPlanVehicle(); vehicle.setTestPlanId(planId); vehicle.setVehicleId(vehicleId); result.add(vehicle); } return result; } }