QDAirPortBackend0122/doc/design/base_info_management_module.md
2026-01-22 13:19:47 +08:00

19 KiB
Raw Blame History

基础信息管理模块设计文档

1. 模块概述

1.1 功能范围

基础信息管理模块负责管理系统中的核心基础实体信息,主要包括:

  • 车辆信息管理:车辆基本信息(车牌号、所属单位、车辆类型)的管理和维护
  • 驾驶员信息管理:驾驶员个人信息及账号管理
  • 关联关系管理:维护车辆与驾驶员之间的关联关系

本模块作为系统的基础数据提供者,为其他功能模块提供支持数据。

1.2 与其他模块的关系

  • 数据采集模块通过车辆ID关联实时位置数据到车辆基础信息
  • 数据处理模块:利用车辆基础信息辅助处理和分析
  • 现有的车辆和驾驶员管理:此模块将扩展现有的移动对象模型,添加额外的管理功能

2. 领域模型设计

2.1 核心实体

2.1.1 车辆实体Vehicle

基于现有的 MovingObjectSpecialVehicle 类进行扩展:

@Entity
@Table(name = "vehicle")
public class Vehicle extends SpecialVehicle {
    @Column(name = "plate_number", nullable = false, unique = true)
    private String plateNumber;         // 车牌号
    
    @Column(name = "organization", nullable = false)
    private String organization;        // 所属单位
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private VehicleStatus status = VehicleStatus.ACTIVE;  // 车辆状态
    
    // 基础审计字段由JPA自动管理
}

public enum VehicleStatus {
    ACTIVE,         // 活跃
    INACTIVE,       // 未激活
    MAINTENANCE,    // 维护中
    SCRAPPED        // 已报废
}

2.1.2 驾驶员实体Driver

@Entity
@Table(name = "driver")
public class Driver {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;
    
    @Column(name = "name", nullable = false)
    private String name;                // 姓名
    
    @Column(name = "license_type")
    private String licenseType;         // 驾驶证类型
    
    @Column(name = "license_number", unique = true)
    private String licenseNumber;       // 驾驶证号码
    
    @Column(name = "phone_number")
    private String phoneNumber;         // 联系电话
    
    @Column(name = "photo_url")
    private String photoUrl;            // 人像照片URL
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private DriverStatus status = DriverStatus.ACTIVE;  // 驾驶员状态
    
    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private Date createTime;
    
    @LastModifiedDate
    @Column(name = "updated_at")
    private Date updateTime;
}

public enum DriverStatus {
    ACTIVE,         // 活跃
    INACTIVE,       // 未激活
    SUSPENDED,      // 已暂停
    RESIGNED        // 已离职
}

2.1.3 车辆分配记录VehicleAssignment

@Entity
@Table(name = "vehicle_assignment")
public class VehicleAssignment {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;
    
    @Column(name = "vehicle_id", nullable = false)
    private String vehicleId;           // 车辆ID
    
    @Column(name = "driver_id", nullable = false)
    private String driverId;            // 驾驶员ID
    
    @Column(name = "start_time", nullable = false)
    private Date startTime;             // 开始时间
    
    @Column(name = "end_time")
    private Date endTime;               // 结束时间(null表示当前分配)
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private AssignmentStatus status = AssignmentStatus.ACTIVE;
    
    @Column(name = "assigned_by")
    private String assignedBy;          // 分配人
    
    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private Date createTime;
    
    @LastModifiedDate
    @Column(name = "updated_at")
    private Date updateTime;
}

public enum AssignmentStatus {
    ACTIVE,         // 活跃
    COMPLETED,      // 已完成
    CANCELLED       // 已取消
}

3. 模块设计

3.1 包结构

与现有项目保持一致,将模块集成到现有架构中:

com.dongni.collisionavoidance
└── baseinfo/                     # 基础信息管理模块
    ├── controller/               # REST API控制器
    ├── repository/               # 数据访问层
    ├── entity/                   # 实体类
    └── service/                  # 业务逻辑服务
        ├── VehicleService.java
        ├── DriverService.java
        └── VehicleAssignmentService.java

3.2 数据访问层Repository

@Repository
public interface VehicleRepository extends JpaRepository<Vehicle, String> {
    // 根据车牌号查找车辆
    Optional<Vehicle> findByPlateNumber(String plateNumber);
    
    // 根据组织机构查找车辆
    List<Vehicle> findByOrganization(String organization);
    
    // 根据状态查找车辆
    List<Vehicle> findByStatus(VehicleStatus status);
}

@Repository
public interface DriverRepository extends JpaRepository<Driver, String> {
    // 根据驾驶证号码查找驾驶员
    Optional<Driver> findByLicenseNumber(String licenseNumber);
    
    // 根据姓名查找驾驶员(模糊查询)
    List<Driver> findByNameContaining(String name);
}

@Repository
public interface VehicleAssignmentRepository extends JpaRepository<VehicleAssignment, String> {
    // 查找指定车辆的当前分配(无结束时间)
    Optional<VehicleAssignment> findByVehicleIdAndEndTimeIsNullAndStatus(String vehicleId, AssignmentStatus status);
    
    // 查找指定驾驶员的历史分配记录
    List<VehicleAssignment> findByDriverIdOrderByStartTimeDesc(String driverId);
}

3.3 服务层Service

3.3.1 VehicleService

@Service
@Slf4j
public class VehicleService {
    private final VehicleRepository vehicleRepository;
    
    @Autowired
    public VehicleService(VehicleRepository vehicleRepository) {
        this.vehicleRepository = vehicleRepository;
    }
    
    // 创建新车辆
    public Vehicle createVehicle(Vehicle vehicle) {
        log.info("创建新车辆: {}", vehicle.getPlateNumber());
        return vehicleRepository.save(vehicle);
    }
    
    // 根据ID查找车辆
    public Optional<Vehicle> findById(String id) {
        return vehicleRepository.findById(id);
    }
    
    // 根据车牌号查找车辆
    public Optional<Vehicle> findByPlateNumber(String plateNumber) {
        return vehicleRepository.findByPlateNumber(plateNumber);
    }
    
    // 更新车辆信息
    public Vehicle updateVehicle(String id, Vehicle vehicleDetails) {
        return vehicleRepository.findById(id)
            .map(vehicle -> {
                if (vehicleDetails.getPlateNumber() != null) {
                    vehicle.setPlateNumber(vehicleDetails.getPlateNumber());
                }
                if (vehicleDetails.getOrganization() != null) {
                    vehicle.setOrganization(vehicleDetails.getOrganization());
                }
                if (vehicleDetails.getStatus() != null) {
                    vehicle.setStatus(vehicleDetails.getStatus());
                }
                return vehicleRepository.save(vehicle);
            })
            .orElseThrow(() -> new EntityNotFoundException("Vehicle not found with id " + id));
    }
    
    // 删除车辆
    public void deleteVehicle(String id) {
        vehicleRepository.deleteById(id);
    }
    
    // 获取全部车辆
    public List<Vehicle> getAllVehicles() {
        return vehicleRepository.findAll();
    }
    
    // 根据组织查找车辆
    public List<Vehicle> findByOrganization(String organization) {
        return vehicleRepository.findByOrganization(organization);
    }
}

3.3.2 DriverService

@Service
@Slf4j
public class DriverService {
    private final DriverRepository driverRepository;
    
    @Autowired
    public DriverService(DriverRepository driverRepository) {
        this.driverRepository = driverRepository;
    }
    
    // 创建新驾驶员
    public Driver createDriver(Driver driver) {
        log.info("创建新驾驶员: {}", driver.getName());
        return driverRepository.save(driver);
    }
    
    // 根据ID查找驾驶员
    public Optional<Driver> findById(String id) {
        return driverRepository.findById(id);
    }
    
    // 更新驾驶员信息
    public Driver updateDriver(String id, Driver driverDetails) {
        return driverRepository.findById(id)
            .map(driver -> {
                if (driverDetails.getName() != null) {
                    driver.setName(driverDetails.getName());
                }
                if (driverDetails.getLicenseType() != null) {
                    driver.setLicenseType(driverDetails.getLicenseType());
                }
                if (driverDetails.getPhoneNumber() != null) {
                    driver.setPhoneNumber(driverDetails.getPhoneNumber());
                }
                if (driverDetails.getStatus() != null) {
                    driver.setStatus(driverDetails.getStatus());
                }
                return driverRepository.save(driver);
            })
            .orElseThrow(() -> new EntityNotFoundException("Driver not found with id " + id));
    }
    
    // 删除驾驶员
    public void deleteDriver(String id) {
        driverRepository.deleteById(id);
    }
    
    // 获取全部驾驶员
    public List<Driver> getAllDrivers() {
        return driverRepository.findAll();
    }
    
    // 根据姓名模糊查询驾驶员
    public List<Driver> findByNameContaining(String name) {
        return driverRepository.findByNameContaining(name);
    }
}

3.3.3 VehicleAssignmentService

@Service
@Slf4j
public class VehicleAssignmentService {
    private final VehicleAssignmentRepository assignmentRepository;
    private final VehicleRepository vehicleRepository;
    private final DriverRepository driverRepository;
    
    @Autowired
    public VehicleAssignmentService(
            VehicleAssignmentRepository assignmentRepository,
            VehicleRepository vehicleRepository,
            DriverRepository driverRepository) {
        this.assignmentRepository = assignmentRepository;
        this.vehicleRepository = vehicleRepository;
        this.driverRepository = driverRepository;
    }
    
    // 分配车辆给驾驶员
    @Transactional
    public VehicleAssignment assignVehicleToDriver(VehicleAssignment assignment) {
        // 验证车辆存在
        vehicleRepository.findById(assignment.getVehicleId())
            .orElseThrow(() -> new EntityNotFoundException("Vehicle not found"));
            
        // 验证驾驶员存在
        driverRepository.findById(assignment.getDriverId())
            .orElseThrow(() -> new EntityNotFoundException("Driver not found"));
            
        // 检查车辆是否已分配
        Optional<VehicleAssignment> existingAssignment = 
            assignmentRepository.findByVehicleIdAndEndTimeIsNullAndStatus(
                assignment.getVehicleId(), AssignmentStatus.ACTIVE);
                
        if (existingAssignment.isPresent()) {
            throw new IllegalStateException("Vehicle is already assigned");
        }
        
        log.info("分配车辆 {} 给驾驶员 {}", assignment.getVehicleId(), assignment.getDriverId());
        return assignmentRepository.save(assignment);
    }
    
    // 结束车辆分配
    @Transactional
    public VehicleAssignment endAssignment(String assignmentId, Date endTime) {
        VehicleAssignment assignment = assignmentRepository.findById(assignmentId)
            .orElseThrow(() -> new EntityNotFoundException("Assignment not found"));
            
        if (assignment.getEndTime() != null) {
            throw new IllegalStateException("Assignment already ended");
        }
        
        assignment.setEndTime(endTime);
        assignment.setStatus(AssignmentStatus.COMPLETED);
        
        log.info("结束车辆分配: {}", assignmentId);
        return assignmentRepository.save(assignment);
    }
    
    // 查找车辆的当前分配
    public Optional<VehicleAssignment> findCurrentAssignmentForVehicle(String vehicleId) {
        return assignmentRepository.findByVehicleIdAndEndTimeIsNullAndStatus(
            vehicleId, AssignmentStatus.ACTIVE);
    }
    
    // 查找驾驶员的分配历史
    public List<VehicleAssignment> findAssignmentHistoryForDriver(String driverId) {
        return assignmentRepository.findByDriverIdOrderByStartTimeDesc(driverId);
    }
}

3.4 REST API控制器Controller

3.4.1 VehicleController

@RestController
@RequestMapping("/api/vehicles")
@Slf4j
public class VehicleController {
    private final VehicleService vehicleService;
    
    @Autowired
    public VehicleController(VehicleService vehicleService) {
        this.vehicleService = vehicleService;
    }
    
    // 创建新车辆
    @PostMapping
    public ResponseEntity<Vehicle> createVehicle(@RequestBody Vehicle vehicle) {
        Vehicle createdVehicle = vehicleService.createVehicle(vehicle);
        return new ResponseEntity<>(createdVehicle, HttpStatus.CREATED);
    }
    
    // 获取所有车辆
    @GetMapping
    public ResponseEntity<List<Vehicle>> getAllVehicles(
            @RequestParam(required = false) String organization) {
        List<Vehicle> vehicles;
        
        if (organization != null && !organization.isEmpty()) {
            vehicles = vehicleService.findByOrganization(organization);
        } else {
            vehicles = vehicleService.getAllVehicles();
        }
        
        return ResponseEntity.ok(vehicles);
    }
    
    // 根据ID获取车辆
    @GetMapping("/{id}")
    public ResponseEntity<Vehicle> getVehicleById(@PathVariable String id) {
        return vehicleService.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
    
    // 更新车辆
    @PutMapping("/{id}")
    public ResponseEntity<Vehicle> updateVehicle(
            @PathVariable String id, 
            @RequestBody Vehicle vehicleDetails) {
        try {
            Vehicle updatedVehicle = vehicleService.updateVehicle(id, vehicleDetails);
            return ResponseEntity.ok(updatedVehicle);
        } catch (EntityNotFoundException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    // 删除车辆
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteVehicle(@PathVariable String id) {
        vehicleService.deleteVehicle(id);
        return ResponseEntity.noContent().build();
    }
    
    // 根据车牌号查找车辆
    @GetMapping("/plateNumber/{plateNumber}")
    public ResponseEntity<Vehicle> getVehicleByPlateNumber(@PathVariable String plateNumber) {
        return vehicleService.findByPlateNumber(plateNumber)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
}

其他控制器DriverController、VehicleAssignmentController也采用类似的RESTful设计模式。

4. 数据库设计

4.1 车辆表vehicle

CREATE TABLE vehicle (
    id VARCHAR(36) PRIMARY KEY,
    plate_number VARCHAR(20) NOT NULL UNIQUE,
    organization VARCHAR(100) NOT NULL,
    type VARCHAR(20) NOT NULL,
    status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    INDEX idx_plate_number (plate_number),
    INDEX idx_organization (organization),
    INDEX idx_status (status)
);

4.2 驾驶员表driver

CREATE TABLE driver (
    id VARCHAR(36) PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    license_type VARCHAR(20),
    license_number VARCHAR(50) UNIQUE,
    phone_number VARCHAR(20),
    photo_url VARCHAR(255),
    status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    INDEX idx_license_number (license_number),
    INDEX idx_name (name),
    INDEX idx_status (status)
);

4.3 车辆分配表vehicle_assignment

CREATE TABLE vehicle_assignment (
    id VARCHAR(36) PRIMARY KEY,
    vehicle_id VARCHAR(36) NOT NULL,
    driver_id VARCHAR(36) NOT NULL,
    start_time TIMESTAMP NOT NULL,
    end_time TIMESTAMP NULL,
    status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
    assigned_by VARCHAR(36),
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    FOREIGN KEY (vehicle_id) REFERENCES vehicle(id),
    FOREIGN KEY (driver_id) REFERENCES driver(id),
    INDEX idx_vehicle_id (vehicle_id),
    INDEX idx_driver_id (driver_id),
    INDEX idx_status_end_time (status, end_time)
);

5. 与现有模块的集成

5.1 与数据采集模块集成

基础信息管理模块提供的车辆信息将与数据采集模块获取的实时位置数据相关联:

// 在数据采集模块中使用车辆信息
@Service
public class EnhancedDataCollectorService {
    private final VehicleService vehicleService;
    // ...其他依赖项
    
    @Autowired
    public EnhancedDataCollectorService(VehicleService vehicleService, /* 其他依赖 */) {
        this.vehicleService = vehicleService;
        // ...
    }
    
    // 处理位置数据时,关联车辆基础信息
    private void processVehicleData(VehicleLocationInfo locationInfo) {
        // 通过车牌号查找车辆基础信息
        vehicleService.findByPlateNumber(locationInfo.getPlateNumber())
            .ifPresent(vehicle -> {
                // 关联基础信息到位置数据
                locationInfo.setOrganization(vehicle.getOrganization());
                locationInfo.setVehicleType(vehicle.getVehicleType());
                // ...其他关联
            });
            
        // 继续处理位置数据...
    }
}

5.2 与前端显示集成

车辆和驾驶员的基础信息将通过WebSocket通信模块传递给前端用于增强显示效果

// 在WebSocket处理中关联基础信息
@Service
public class WebSocketMessageService {
    private final VehicleService vehicleService;
    // ...
    
    // 构建消息时集成车辆基础信息
    public VehicleStatusMessage buildVehicleStatusMessage(VehicleLocationInfo locationInfo) {
        VehicleStatusMessage message = new VehicleStatusMessage();
        // 设置位置信息
        message.setLocation(locationInfo.getPosition());
        message.setSpeed(locationInfo.getSpeed());
        
        // 关联基础信息
        vehicleService.findById(locationInfo.getVehicleId())
            .ifPresent(vehicle -> {
                message.setPlateNumber(vehicle.getPlateNumber());
                message.setOrganization(vehicle.getOrganization());
                // 其他基础信息...
            });
            
        return message;
    }
}

6. 总结

基础信息管理模块设计遵循了以下原则:

  1. 与现有系统集成:模块设计考虑了与现有移动对象模型的集成,扩展而非替代现有功能
  2. 聚焦核心需求:专注于车辆信息、驾驶员信息和关联关系的管理,不重复实现现有功能
  3. 遵循统一架构:采用与系统其他部分一致的分层架构和设计模式
  4. 扩展性考虑:设计支持未来功能扩展,如车辆健康状态监控等