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.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.*;
|
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.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;
|
|
/**
|
* <p>
|
* 巡游计划 服务实现类
|
* </p>
|
*
|
* @author mitao
|
* @since 2026-02-26
|
*/
|
@Service
|
@RequiredArgsConstructor(onConstructor_ = @Lazy)
|
public class XpCruisePlanServiceImpl extends ServiceImpl<XpCruisePlanMapper, XpCruisePlan> implements IXpCruisePlanService {
|
|
private final IXpCruisePlanPointService xpCruisePlanPointService;
|
private final IXpCruisePlanVehicleService xpCruisePlanVehicleService;
|
private final XpPointService 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());
|
Page<XpCruisePlan> page = lambdaQuery()
|
.like(StringUtils.isNotBlank(query.getPlanName()), XpCruisePlan::getPlanName, query.getPlanName())
|
.orderByDesc(XpCruisePlan::getCreateTime)
|
.page(pageInfo);
|
|
//收集巡游计划ID
|
List<Long> planIds = page.getRecords().stream().map(XpCruisePlan::getId).collect(Collectors.toList());
|
// 批量查询巡游计划点位和车辆信息,并组装到巡游计划对象中
|
Map<Long, List<XpCruisePlanPoint>> pointMap = CollUtil.isNotEmpty(planIds) ? xpCruisePlanPointService.lambdaQuery().in(XpCruisePlanPoint::getCruisePlanId, planIds)
|
.list().stream().collect(Collectors.groupingBy(XpCruisePlanPoint::getCruisePlanId)) : Collections.emptyMap();
|
Map<Long, List<XpCruisePlanVehicle>> vehicleMap = CollUtil.isNotEmpty(planIds) ? xpCruisePlanVehicleService.lambdaQuery().in(XpCruisePlanVehicle::getCruisePlanId, planIds)
|
.list().stream().collect(Collectors.groupingBy(XpCruisePlanVehicle::getCruisePlanId)) : Collections.emptyMap();
|
page.getRecords().forEach(plan -> {
|
plan.setPointNum(pointMap.get(plan.getId()).size());
|
plan.setVehicleNum(vehicleMap.get(plan.getId()).size());
|
});
|
pageInfo.setRecords(page.getRecords());
|
return pageInfo;
|
}
|
|
@Override
|
@Transactional
|
@ShardingSphereTransactionType(TransactionType.BASE)
|
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());
|
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
|
@ShardingSphereTransactionType(TransactionType.BASE)
|
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());
|
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
|
@ShardingSphereTransactionType(TransactionType.BASE)
|
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)
|
.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.getVehicleModelName());
|
}
|
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<Long> 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)) {
|
List<XpVehicle> data = xpVehicleClient.listByIds(boundVehicles.stream().map(XpCruisePlanVehicle::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<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;
|
}
|
}
|