From 1a9aca4e28eb23091b97ba2877b68fade7dfde4e Mon Sep 17 00:00:00 2001
From: “mitao” <“2763622819@qq.com”>
Date: 星期六, 07 三月 2026 21:12:00 +0800
Subject: [PATCH] feat(management):管理后台-车队管理
---
xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpFleetServiceImpl.java | 475 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 473 insertions(+), 2 deletions(-)
diff --git a/xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpFleetServiceImpl.java b/xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpFleetServiceImpl.java
index 276d5e0..c470d31 100644
--- a/xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpFleetServiceImpl.java
+++ b/xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpFleetServiceImpl.java
@@ -1,14 +1,46 @@
package com.xiaopeng.vehicleConvoy.service.impl;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO;
+import com.xiaopeng.api.feignClient.account.XpOperationUserClient;
+import com.xiaopeng.api.feignClient.operation.XpElectronicClient;
+import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
+import com.xiaopeng.api.model.account.XpOperationsUser;
+import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
+import com.xiaopeng.api.model.vehicleConvoy.XpFleetOperations;
+import com.xiaopeng.api.model.vehicleConvoy.XpFleetVehicle;
+import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
+import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO;
+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.vehicleConvoy.constant.I18nKeyConstant;
import com.xiaopeng.vehicleConvoy.mapper.XpFleetMapper;
+import com.xiaopeng.vehicleConvoy.model.dto.FleetAddDTO;
+import com.xiaopeng.vehicleConvoy.model.dto.FleetEditDTO;
+import com.xiaopeng.vehicleConvoy.model.query.FleetPageQuery;
+import com.xiaopeng.vehicleConvoy.model.query.FleetUserPageQuery;
+import com.xiaopeng.vehicleConvoy.model.query.FleetVehiclePageQuery;
+import com.xiaopeng.vehicleConvoy.model.vo.FleetDetailVO;
+import com.xiaopeng.vehicleConvoy.model.vo.FleetPageVO;
+import com.xiaopeng.vehicleConvoy.model.vo.FleetUserVO;
+import com.xiaopeng.vehicleConvoy.model.vo.FleetVehicleVO;
+import com.xiaopeng.vehicleConvoy.service.IXpFleetOperationsService;
import com.xiaopeng.vehicleConvoy.service.IXpFleetService;
+import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
/**
* <p>
@@ -19,7 +51,18 @@
* @since 2026-02-03
*/
@Service
+@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class XpFleetServiceImpl extends ServiceImpl<XpFleetMapper, XpFleet> implements IXpFleetService {
+
+ private final IXpFleetOperationsService xpFleetOperationsService;
+
+ private final IXpFleetVehicleService xpFleetVehicleService;
+
+ private final XpOperationUserClient xpOperationUserClient;
+
+ private final XpVehicleClient xpVehicleClient;
+
+ private final XpElectronicClient xpElectronicClient;
@Override
public List<XpFleet> listByIds(List<Long> ids) {
@@ -28,4 +71,432 @@
}
return super.listByIds(ids);
}
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public R<Void> add(FleetAddDTO dto) {
+ // 1. 校验车队名称不能重复
+ long count = this.count(new LambdaQueryWrapper<XpFleet>()
+ .eq(XpFleet::getFleetName, dto.getFleetName()));
+ if (count > 0) {
+ throw new ServiceException("车队名称已存在");
+ }
+
+ // 2. 校验运维人员绑定
+ validateUserBinding(dto.getOperationsUserIds(), null);
+
+ // 3. 校验车辆绑定
+ validateVehicleBinding(dto.getVehicleIds(), null);
+
+ // 4. 插入车队主表记录
+ XpFleet fleet = new XpFleet();
+ fleet.setFleetName(dto.getFleetName());
+ fleet.setOperationsUserId(dto.getOperationsUserId());
+ fleet.setLocationId(dto.getLocationId());
+ this.save(fleet);
+
+ // 5. 批量插入车队-人员关联表
+ List<XpFleetOperations> operationsList = dto.getOperationsUserIds().stream()
+ .map(userId -> {
+ XpFleetOperations operations = new XpFleetOperations();
+ operations.setFleetId(fleet.getId());
+ operations.setOperationsUserId(userId);
+ return operations;
+ }).collect(Collectors.toList());
+ if (!CollectionUtils.isEmpty(operationsList)) {
+ xpFleetOperationsService.saveBatch(operationsList);
+ }
+
+ // 6. 批量插入车队-车辆关联表
+ List<XpFleetVehicle> vehicleList = dto.getVehicleIds().stream()
+ .map(vehicleId -> {
+ XpFleetVehicle fleetVehicle = new XpFleetVehicle();
+ fleetVehicle.setFleetId(fleet.getId());
+ fleetVehicle.setVehicleId(vehicleId);
+ return fleetVehicle;
+ }).collect(Collectors.toList());
+ if (!CollectionUtils.isEmpty(vehicleList)) {
+ xpFleetVehicleService.saveBatch(vehicleList);
+ }
+
+ return R.ok();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public R<Void> edit(FleetEditDTO dto) {
+ // 1. 查询车队是否存在
+ XpFleet fleet = this.getById(dto.getId());
+ if (fleet == null) {
+ throw new ServiceException("车队不存在");
+ }
+
+ // 2. 校验车队名称不能与其他车队重复
+ long count = this.count(new LambdaQueryWrapper<XpFleet>()
+ .eq(XpFleet::getFleetName, dto.getFleetName())
+ .ne(XpFleet::getId, dto.getId()));
+ if (count > 0) {
+ throw new ServiceException("车队名称已存在");
+ }
+
+ // 3. 校验负责人绑定(如果修改了负责人)
+ if (!dto.getOperationsUserId().equals(fleet.getOperationsUserId())) {
+ List<Long> userIds = new ArrayList<>();
+ userIds.add(dto.getOperationsUserId());
+ validateUserBinding(userIds, dto.getId());
+ }
+
+ // 4. 更新车队主表记录
+ fleet.setFleetName(dto.getFleetName());
+ fleet.setOperationsUserId(dto.getOperationsUserId());
+ fleet.setLocationId(dto.getLocationId());
+ this.updateById(fleet);
+
+ return R.ok();
+ }
+
+ /**
+ * 校验人员绑定
+ *
+ * @param userIds 人员ID列表
+ * @param excludeFleetId 排除的车队ID(编辑时使用)
+ */
+ private void validateUserBinding(List<Long> userIds, Long excludeFleetId) {
+ if (CollectionUtils.isEmpty(userIds)) {
+ return;
+ }
+
+ for (Long userId : userIds) {
+ LambdaQueryWrapper<XpFleetOperations> wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(XpFleetOperations::getOperationsUserId, userId);
+ if (excludeFleetId != null) {
+ wrapper.ne(XpFleetOperations::getFleetId, excludeFleetId);
+ }
+ XpFleetOperations operations = xpFleetOperationsService.getOne(wrapper);
+ if (operations != null) {
+ // 查询人员姓名和车队名称
+ R<XpOperationsUser> userResult = xpOperationUserClient.queryById(userId);
+ XpFleet fleet = this.getById(operations.getFleetId());
+ String userName = userResult.getData() != null ? userResult.getData().getNickName() : "未知";
+ String fleetName = fleet != null ? fleet.getFleetName() : "未知";
+ List<Object> argsList = new ArrayList<>();
+ argsList.add(userName);
+ argsList.add(fleetName);
+ Object[] args = argsList.toArray();
+ throw new ServiceException("运维人员" + userName + "已绑定车队" + fleetName, I18nKeyConstant.FLEET_OPERATION_USER_BOUND_V1, args);
+ }
+ }
+ }
+
+ /**
+ * 校验车辆绑定
+ *
+ * @param vehicleIds 车辆ID列表
+ * @param excludeFleetId 排除的车队ID(编辑时使用)
+ */
+ private void validateVehicleBinding(List<Long> vehicleIds, Long excludeFleetId) {
+ if (CollectionUtils.isEmpty(vehicleIds)) {
+ return;
+ }
+
+ for (Long vehicleId : vehicleIds) {
+ LambdaQueryWrapper<XpFleetVehicle> wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(XpFleetVehicle::getVehicleId, vehicleId);
+ if (excludeFleetId != null) {
+ wrapper.ne(XpFleetVehicle::getFleetId, excludeFleetId);
+ }
+ XpFleetVehicle fleetVehicle = xpFleetVehicleService.getOne(wrapper);
+ if (fleetVehicle != null) {
+ // 查询车牌号和车队名称
+ R<XpVehicle> vehicleResult = xpVehicleClient.queryById(vehicleId);
+ XpFleet fleet = this.getById(fleetVehicle.getFleetId());
+ String plateNumber = vehicleResult.getData() != null ? vehicleResult.getData().getPlateNumber() : "未知";
+ String fleetName = fleet != null ? fleet.getFleetName() : "未知";
+ List<Object> argList = new ArrayList<>();
+ argList.add(plateNumber);
+ argList.add(fleetName);
+ throw new ServiceException("车辆[" + plateNumber + "]已绑定车队[" + fleetName + "]", I18nKeyConstant.FLEET_VEHICLE_BOUND_V1, argList.toArray());
+ }
+ }
+ }
+
+ @Override
+ public R<FleetDetailVO> queryById(Long id) {
+ // 1. 查询车队主表
+ XpFleet fleet = this.getById(id);
+ if (fleet == null) {
+ throw new ServiceException("车队不存在");
+ }
+
+ // 2. 组装VO
+ FleetDetailVO vo = new FleetDetailVO();
+ BeanUtils.copyProperties(fleet, vo);
+
+ // 3. 统计人员数量
+ long userCount = xpFleetOperationsService.count(new LambdaQueryWrapper<XpFleetOperations>()
+ .eq(XpFleetOperations::getFleetId, id));
+ vo.setUserCount((int) userCount);
+
+ // 4. 统计车辆数量
+ long vehicleCount = xpFleetVehicleService.count(new LambdaQueryWrapper<XpFleetVehicle>()
+ .eq(XpFleetVehicle::getFleetId, id));
+ vo.setVehicleCount((int) vehicleCount);
+
+ // 5. 查询负责人信息
+ if (fleet.getOperationsUserId() != null) {
+ R<XpOperationsUser> userResult = xpOperationUserClient.queryById(fleet.getOperationsUserId());
+ if (userResult.getData() != null) {
+ vo.setOperationsUserName(userResult.getData().getNickName());
+ }
+ }
+
+ return R.ok(vo);
+ }
+
+ @Override
+ public R<PageInfo<FleetPageVO>> pageList(FleetPageQuery query) {
+ // 1. 构建查询条件
+ LambdaQueryWrapper<XpFleet> wrapper = new LambdaQueryWrapper<>();
+ if (StringUtils.isNotBlank(query.getFleetName())) {
+ wrapper.like(XpFleet::getFleetName, query.getFleetName());
+ }
+ wrapper.orderByDesc(XpFleet::getCreateTime);
+
+ // 2. 执行分页查询
+ Page<XpFleet> page = new Page<>(query.getPageNum(), query.getPageSize());
+ Page<XpFleet> resultPage = this.page(page, wrapper);
+
+ // 3. 收集所有需要查询的ID
+ List<Long> userIds = resultPage.getRecords().stream()
+ .map(XpFleet::getOperationsUserId)
+ .filter(Objects::nonNull)
+ .distinct()
+ .collect(Collectors.toList());
+
+ List<Long> electronicIds = resultPage.getRecords().stream()
+ .map(XpFleet::getElectronicId)
+ .filter(Objects::nonNull)
+ .distinct()
+ .collect(Collectors.toList());
+
+ // 4. 批量查询负责人信息并转换为Map
+ Map<Long, XpOperationsUser> userMap = new HashMap<>();
+ if (!CollectionUtils.isEmpty(userIds)) {
+ R<List<XpOperationsUser>> usersResult = xpOperationUserClient.listByIds(userIds);
+ if (usersResult.getData() != null) {
+ userMap = usersResult.getData().stream()
+ .collect(Collectors.toMap(XpOperationsUser::getId, user -> user));
+ }
+ }
+
+ // 5. 批量查询围栏信息并转换为Map
+ Map<Long, XpElectronicFence> fenceMap = new HashMap<>();
+ if (!CollectionUtils.isEmpty(electronicIds)) {
+ R<List<XpElectronicFence>> fencesResult = xpElectronicClient.listByIds(electronicIds);
+ if (fencesResult.getData() != null) {
+ fenceMap = fencesResult.getData().stream()
+ .collect(Collectors.toMap(XpElectronicFence::getId, fence -> fence));
+ }
+ }
+
+ // 6. 转换为VO并填充信息
+ List<FleetPageVO> records = new ArrayList<>();
+ for (XpFleet fleet : resultPage.getRecords()) {
+ FleetPageVO vo = new FleetPageVO();
+ BeanUtils.copyProperties(fleet, vo);
+
+ // 统计人员数量
+ long userCount = xpFleetOperationsService.count(new LambdaQueryWrapper<XpFleetOperations>()
+ .eq(XpFleetOperations::getFleetId, fleet.getId()));
+ vo.setUserCount((int) userCount);
+
+ // 统计车辆数量
+ long vehicleCount = xpFleetVehicleService.count(new LambdaQueryWrapper<XpFleetVehicle>()
+ .eq(XpFleetVehicle::getFleetId, fleet.getId()));
+ vo.setVehicleCount((int) vehicleCount);
+
+ // 从Map中获取负责人信息
+ if (fleet.getOperationsUserId() != null) {
+ XpOperationsUser user = userMap.get(fleet.getOperationsUserId());
+ if (user != null) {
+ vo.setOperationsUserName(user.getNickName());
+ vo.setPhoneNumber(user.getPhoneNumber());
+ }
+ }
+
+ // 从Map中获取围栏名称
+ if (fleet.getElectronicId() != null) {
+ XpElectronicFence fence = fenceMap.get(fleet.getElectronicId());
+ if (fence != null) {
+ vo.setElectronicName(fence.getElectronicName());
+ }
+ }
+
+ records.add(vo);
+ }
+
+ // 7. 构建分页结果
+ PageInfo<FleetPageVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
+ pageInfo.setRecords(records);
+ pageInfo.setTotal(resultPage.getTotal());
+ return R.ok(pageInfo);
+ }
+
+ @Override
+ public R<PageInfo<FleetVehicleVO>> queryVehiclePageList(FleetVehiclePageQuery query) {
+ // 1. 查询车队-车辆关联表
+ LambdaQueryWrapper<XpFleetVehicle> wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(XpFleetVehicle::getFleetId, query.getFleetId());
+
+ Page<XpFleetVehicle> page = new Page<>(query.getPageNum(), query.getPageSize());
+ Page<XpFleetVehicle> resultPage = xpFleetVehicleService.page(page, wrapper);
+
+ // 2. 获取车辆ID列表
+ List<Long> vehicleIds = resultPage.getRecords().stream()
+ .map(XpFleetVehicle::getVehicleId)
+ .collect(Collectors.toList());
+
+ // 3. 批量查询车辆信息
+ List<FleetVehicleVO> records = new ArrayList<>();
+ if (!CollectionUtils.isEmpty(vehicleIds)) {
+ R<List<XpVehicle>> vehiclesResult = xpVehicleClient.listByIds(vehicleIds);
+ if (vehiclesResult.getData() != null) {
+ for (XpVehicle vehicle : vehiclesResult.getData()) {
+ // 如果有车牌号筛选条件,进行过滤
+ if (StringUtils.isNotBlank(query.getPlateNumber()) &&
+ !vehicle.getPlateNumber().contains(query.getPlateNumber())) {
+ continue;
+ }
+
+ FleetVehicleVO vo = new FleetVehicleVO();
+ vo.setVehicleId(vehicle.getId());
+ vo.setVehicleCode(vehicle.getVehicleCode());
+ vo.setPlateNumber(vehicle.getPlateNumber());
+ vo.setVehicleColor(vehicle.getVehicleColor());
+ vo.setVehicleModel(vehicle.getVehicleModel());
+ vo.setOperatingStatus(vehicle.getOperatingStatus());
+ records.add(vo);
+ }
+ }
+ }
+
+ // 4. 构建分页结果
+ PageInfo<FleetVehicleVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
+ pageInfo.setRecords(records);
+ pageInfo.setTotal(resultPage.getTotal());
+ return R.ok(pageInfo);
+ }
+
+ @Override
+ public R<PageInfo<FleetUserVO>> queryUserPageList(FleetUserPageQuery query) {
+ // 1. 先根据条件查询符合条件的运维用户
+ List<Long> filteredUserIds = new ArrayList<>();
+ if (StringUtils.isNotBlank(query.getNickName()) ||
+ StringUtils.isNotBlank(query.getPhone()) ||
+ query.getRoleId() != null) {
+
+ // 构建查询条件
+ XpOperationsUserQueryDTO queryDTO = new XpOperationsUserQueryDTO();
+ queryDTO.setNickName(query.getNickName());
+ queryDTO.setPhoneNumber(query.getPhone());
+ queryDTO.setRoleId(query.getRoleId());
+
+ // 远程查询符合条件的用户
+ R<List<XpOperationsUserWithRoleVO>> usersResult = xpOperationUserClient.queryByConditions(queryDTO);
+ if (usersResult.getData() == null || usersResult.getData().isEmpty()) {
+ // 没有符合条件的用户,直接返回空结果
+ PageInfo<FleetUserVO> emptyPageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
+ emptyPageInfo.setRecords(new ArrayList<>());
+ emptyPageInfo.setTotal(0L);
+ return R.ok(emptyPageInfo);
+ }
+
+ // 收集用户ID列表
+ filteredUserIds = usersResult.getData().stream()
+ .map(XpOperationsUserWithRoleVO::getId)
+ .collect(Collectors.toList());
+ }
+
+ // 2. 查询车队-人员关联表(使用用户ID列表作为条件)
+ LambdaQueryWrapper<XpFleetOperations> wrapper = new LambdaQueryWrapper<>();
+ if (query.getFleetId() != null) {
+ wrapper.eq(XpFleetOperations::getFleetId, query.getFleetId());
+ }
+ // 如果有用户ID过滤条件,添加到查询中
+ if (!CollectionUtils.isEmpty(filteredUserIds)) {
+ wrapper.in(XpFleetOperations::getOperationsUserId, filteredUserIds);
+ }
+
+ Page<XpFleetOperations> page = new Page<>(query.getPageNum(), query.getPageSize());
+ Page<XpFleetOperations> resultPage = xpFleetOperationsService.page(page, wrapper);
+
+ // 3. 获取人员ID列表
+ List<Long> userIds = resultPage.getRecords().stream()
+ .map(XpFleetOperations::getOperationsUserId)
+ .collect(Collectors.toList());
+
+ // 4. 批量查询人员及角色信息
+ List<FleetUserVO> records = new ArrayList<>();
+ if (!CollectionUtils.isEmpty(userIds)) {
+ R<List<XpOperationsUserWithRoleVO>> usersResult = xpOperationUserClient.listByIdsWithRole(userIds);
+ if (usersResult.getData() != null) {
+ for (XpOperationsUserWithRoleVO user : usersResult.getData()) {
+ FleetUserVO vo = new FleetUserVO();
+ vo.setUserId(user.getId());
+ vo.setNickName(user.getNickName());
+ vo.setPhoneNumber(user.getPhoneNumber());
+ vo.setJobNumber(user.getUniqueNumber());
+ vo.setRoleName(user.getRoleName());
+ records.add(vo);
+ }
+ }
+ }
+
+ // 5. 构建分页结果
+ PageInfo<FleetUserVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
+ pageInfo.setRecords(records);
+ pageInfo.setTotal(resultPage.getTotal());
+ return R.ok(pageInfo);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteById(Long id) {
+ // 删除用户关联
+ xpFleetOperationsService.lambdaUpdate().eq(XpFleetOperations::getFleetId, id).remove();
+ // 删除车辆关联
+ xpFleetVehicleService.lambdaUpdate().eq(XpFleetVehicle::getFleetId, id).remove();
+ // 删除车队
+ removeById(id);
+ }
+
+ @Override
+ public void addVehicle(Long fleetId, Long vehicleId) {
+ // 查询是否已关联
+ Long count = xpFleetVehicleService.lambdaQuery().eq(XpFleetVehicle::getFleetId, fleetId)
+ .eq(XpFleetVehicle::getVehicleId, vehicleId).count();
+ if (count > 0) {
+ throw new ServiceException("当前车队已和该车辆关联", I18nKeyConstant.FLEET_VEHICLE_BOUND_V2);
+ }
+ //保存关联关系
+ XpFleetVehicle xpFleetVehicle = new XpFleetVehicle();
+ xpFleetVehicle.setFleetId(fleetId);
+ xpFleetVehicle.setVehicleId(vehicleId);
+ xpFleetVehicleService.save(xpFleetVehicle);
+ }
+
+ @Override
+ public void addOperationUserId(Long fleetId, Long operationUserId) {
+ // 查询是否已关联
+ Long count = xpFleetOperationsService.lambdaQuery().eq(XpFleetOperations::getFleetId, fleetId)
+ .eq(XpFleetOperations::getOperationsUserId, operationUserId).count();
+ if (count > 0) {
+ throw new ServiceException("当前车队已和该人员关联", I18nKeyConstant.FLEET_OPERATION_USER_BOUND_2);
+ }
+ //保存关联
+ XpFleetOperations operations = new XpFleetOperations();
+ operations.setFleetId(fleetId);
+ operations.setOperationsUserId(operationUserId);
+ xpFleetOperationsService.save(operations);
+ }
}
--
Gitblit v1.7.1