From f9238e18d1ac9247d4ba09197f7e4cc98fa69288 Mon Sep 17 00:00:00 2001 From: Tian jianyong <11429339@qq.com> Date: Thu, 1 May 2025 16:16:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E7=AE=A1=E7=90=86=E8=AE=BE=E8=AE=A1=E6=96=B9?= =?UTF-8?q?=E6=A1=88=EF=BC=8C=E5=8C=85=E6=8B=AC=E8=BD=A6=E8=BE=86=E3=80=81?= =?UTF-8?q?=E5=8F=B8=E6=9C=BA=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/design/base_info_management_module.md | 612 ++++++++++++++++++++++ doc/requirement/requirements.md | 20 + 2 files changed, 632 insertions(+) create mode 100644 doc/design/base_info_management_module.md diff --git a/doc/design/base_info_management_module.md b/doc/design/base_info_management_module.md new file mode 100644 index 0000000..de9a18a --- /dev/null +++ b/doc/design/base_info_management_module.md @@ -0,0 +1,612 @@ +# 基础信息管理模块设计文档 + +## 1. 模块概述 + +### 1.1 功能范围 + +基础信息管理模块负责管理系统中的核心基础实体信息,主要包括: + +- 车辆信息管理:车辆基本信息(车牌号、所属单位、车辆类型)的管理和维护 +- 驾驶员信息管理:驾驶员个人信息及账号管理 +- 关联关系管理:维护车辆与驾驶员之间的关联关系 + +本模块作为系统的基础数据提供者,为其他功能模块提供支持数据。 + +### 1.2 与其他模块的关系 + +- **数据采集模块**:通过车辆ID关联实时位置数据到车辆基础信息 +- **数据处理模块**:利用车辆基础信息辅助处理和分析 +- **现有的车辆和驾驶员管理**:此模块将扩展现有的移动对象模型,添加额外的管理功能 + +## 2. 领域模型设计 + +### 2.1 核心实体 + +#### 2.1.1 车辆实体(Vehicle) + +基于现有的 `MovingObject` 和 `SpecialVehicle` 类进行扩展: + +```java +@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) + +```java +@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) + +```java +@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) + +```java +@Repository +public interface VehicleRepository extends JpaRepository { + // 根据车牌号查找车辆 + Optional findByPlateNumber(String plateNumber); + + // 根据组织机构查找车辆 + List findByOrganization(String organization); + + // 根据状态查找车辆 + List findByStatus(VehicleStatus status); +} + +@Repository +public interface DriverRepository extends JpaRepository { + // 根据驾驶证号码查找驾驶员 + Optional findByLicenseNumber(String licenseNumber); + + // 根据姓名查找驾驶员(模糊查询) + List findByNameContaining(String name); +} + +@Repository +public interface VehicleAssignmentRepository extends JpaRepository { + // 查找指定车辆的当前分配(无结束时间) + Optional findByVehicleIdAndEndTimeIsNullAndStatus(String vehicleId, AssignmentStatus status); + + // 查找指定驾驶员的历史分配记录 + List findByDriverIdOrderByStartTimeDesc(String driverId); +} +``` + +### 3.3 服务层(Service) + +#### 3.3.1 VehicleService + +```java +@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 findById(String id) { + return vehicleRepository.findById(id); + } + + // 根据车牌号查找车辆 + public Optional 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 getAllVehicles() { + return vehicleRepository.findAll(); + } + + // 根据组织查找车辆 + public List findByOrganization(String organization) { + return vehicleRepository.findByOrganization(organization); + } +} +``` + +#### 3.3.2 DriverService + +```java +@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 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 getAllDrivers() { + return driverRepository.findAll(); + } + + // 根据姓名模糊查询驾驶员 + public List findByNameContaining(String name) { + return driverRepository.findByNameContaining(name); + } +} +``` + +#### 3.3.3 VehicleAssignmentService + +```java +@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 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 findCurrentAssignmentForVehicle(String vehicleId) { + return assignmentRepository.findByVehicleIdAndEndTimeIsNullAndStatus( + vehicleId, AssignmentStatus.ACTIVE); + } + + // 查找驾驶员的分配历史 + public List findAssignmentHistoryForDriver(String driverId) { + return assignmentRepository.findByDriverIdOrderByStartTimeDesc(driverId); + } +} +``` + +### 3.4 REST API控制器(Controller) + +#### 3.4.1 VehicleController + +```java +@RestController +@RequestMapping("/api/vehicles") +@Slf4j +public class VehicleController { + private final VehicleService vehicleService; + + @Autowired + public VehicleController(VehicleService vehicleService) { + this.vehicleService = vehicleService; + } + + // 创建新车辆 + @PostMapping + public ResponseEntity createVehicle(@RequestBody Vehicle vehicle) { + Vehicle createdVehicle = vehicleService.createVehicle(vehicle); + return new ResponseEntity<>(createdVehicle, HttpStatus.CREATED); + } + + // 获取所有车辆 + @GetMapping + public ResponseEntity> getAllVehicles( + @RequestParam(required = false) String organization) { + List vehicles; + + if (organization != null && !organization.isEmpty()) { + vehicles = vehicleService.findByOrganization(organization); + } else { + vehicles = vehicleService.getAllVehicles(); + } + + return ResponseEntity.ok(vehicles); + } + + // 根据ID获取车辆 + @GetMapping("/{id}") + public ResponseEntity getVehicleById(@PathVariable String id) { + return vehicleService.findById(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + // 更新车辆 + @PutMapping("/{id}") + public ResponseEntity 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 deleteVehicle(@PathVariable String id) { + vehicleService.deleteVehicle(id); + return ResponseEntity.noContent().build(); + } + + // 根据车牌号查找车辆 + @GetMapping("/plateNumber/{plateNumber}") + public ResponseEntity getVehicleByPlateNumber(@PathVariable String plateNumber) { + return vehicleService.findByPlateNumber(plateNumber) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } +} +``` + +其他控制器(DriverController、VehicleAssignmentController)也采用类似的RESTful设计模式。 + +## 4. 数据库设计 + +### 4.1 车辆表(vehicle) + +```sql +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) + +```sql +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) + +```sql +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 与数据采集模块集成 + +基础信息管理模块提供的车辆信息将与数据采集模块获取的实时位置数据相关联: + +```java +// 在数据采集模块中使用车辆信息 +@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通信模块传递给前端,用于增强显示效果: + +```java +// 在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. **扩展性考虑**:设计支持未来功能扩展,如车辆健康状态监控等 \ No newline at end of file diff --git a/doc/requirement/requirements.md b/doc/requirement/requirements.md index 7c7f2c3..b086fbe 100644 --- a/doc/requirement/requirements.md +++ b/doc/requirement/requirements.md @@ -2,6 +2,26 @@ ## 需求列表(按时间跟踪) +### 2025-05-01 + +- 需求: +(一)车辆信息 + 1.基本信息:包括车辆车牌号、车辆所属单位、车辆类型。 + 2.行驶信息:需要车辆在某一选定时间段内的移动路径、实时速度。需要轨迹回放和实时追踪。 +(二)驾驶员信息 + 系统平台内录入相关驾驶员信息,姓名、驾驶证类型、联系电话、人像,为每位驾驶员建立账号。 +- 分析: + - 需要获取车辆的实时位置数据 + - 需要对车辆进行轨迹回放 + - 需要车辆基本信息 + - 需要获取驾驶员信息 +- 功能模块: + - 数据采集模块:获取车辆的实时位置数据(具备) + - 数据处理模块:根据车辆的实时位置数据,对车辆进行轨迹回放(新增) + - 数据存储模块:存储车辆的实时位置数据和轨迹回放数据(增加轨迹回放数据)、驾驶员信息(新增)、车辆基本信息(新增) + - 基础信息管理模块:驾驶员信息(新增)、车辆基本信息(新增) + - 通信模块:WebSocket通信(增加轨迹回放事件) + ### 2025-04-25 - 需求:电子围栏,根据机场划定的区域,当车辆进入或离开该区域时,进行预警