diff --git a/.gitignore b/.gitignore
index 2c70b613..4b321ec6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,4 +49,6 @@ logs/
.DS_Store
.vscode/
-Users/
\ No newline at end of file
+Users/
+
+qaup-deploy/
\ No newline at end of file
diff --git a/.kiro/specs/traffic-light-integration/design.md b/.kiro/specs/traffic-light-integration/design.md
new file mode 100644
index 00000000..2dde9b52
--- /dev/null
+++ b/.kiro/specs/traffic-light-integration/design.md
@@ -0,0 +1,464 @@
+# 设计文档
+
+## 概述
+
+红绿灯信号集成功能为QAUP机场管理系统提供实时路口状态监控能力。该功能通过TCP服务器监听外部红绿灯硬件发送的状态信号,解析DI格式的原始数据,转换为系统内部的标准化消息格式,并通过WebSocket实时广播给前端客户端。
+
+该设计遵循现有系统的架构模式,集成到现有的数据采集和WebSocket通信框架中,确保与其他系统组件的一致性和兼容性。
+
+## 架构
+
+### 整体架构图
+
+```mermaid
+graph TB
+ A[红绿灯硬件] -->|TCP连接
端口8082| B[TrafficLightTcpServer]
+ B --> C[TrafficLightDataCollector]
+ C --> D[DataProcessingService]
+ D --> E[TrafficLightSignalParser]
+ E --> F[TrafficLightStatusEvent]
+ F --> G[WebSocketMessageBroadcaster]
+ G -->|WebSocket| H[前端客户端]
+
+ I[Spring配置] --> B
+ J[应用配置文件] --> I
+
+ subgraph "datacollector模块"
+ B
+ C
+ end
+
+ subgraph "dataprocessing模块"
+ D
+ E
+ F
+ end
+
+ subgraph "现有系统组件"
+ G
+ K[UniversalMessage]
+ L[TrafficLightStatusPayload]
+ end
+
+ F --> K
+ F --> L
+```
+
+### 数据流程
+
+1. **信号接收**: TCP服务器(datacollector模块)监听8082端口,接收红绿灯硬件发送的JSON格式信号
+2. **数据采集**: TrafficLightDataCollector收集原始信号数据,传递给数据处理服务
+3. **数据处理**: DataProcessingService(dataprocessing模块)调用信号解析器处理数据
+4. **信号解析**: TrafficLightSignalParser将DI格式的原始信号转换为标准化的红绿灯状态
+5. **事件发布**: 数据处理服务通过Spring事件机制发布红绿灯状态变更事件
+6. **WebSocket广播**: 事件监听器将状态更新广播给所有连接的前端客户端
+
+## 组件和接口
+
+### 1. TrafficLightTcpServer (datacollector模块)
+
+**职责**: TCP服务器,负责监听和接收红绿灯硬件信号
+
+**接口设计**:
+```java
+@Component
+public class TrafficLightTcpServer {
+ // 启动TCP服务器
+ public void startServer();
+
+ // 停止TCP服务器
+ public void stopServer();
+
+ // 处理客户端连接
+ private void handleClientConnection(Socket clientSocket);
+
+ // 获取服务器状态
+ public ServerStatus getServerStatus();
+}
+```
+
+**配置属性**:
+- `traffic.light.tcp.port`: TCP监听端口(默认8082)
+- `traffic.light.tcp.enabled`: 是否启用TCP服务器(默认true)
+- `traffic.light.tcp.max-connections`: 最大连接数(默认10)
+
+### 2. TrafficLightDataCollector (datacollector模块)
+
+**职责**: 集成到现有数据采集框架,收集红绿灯原始数据并传递给数据处理服务
+
+**接口设计**:
+```java
+@Service
+public class TrafficLightDataCollector {
+ // 处理TCP服务器接收到的原始信号
+ public void collectTrafficLightSignal(String rawJsonSignal);
+
+ // 获取采集统计信息
+ public CollectionStatistics getStatistics();
+}
+```
+
+### 3. TrafficLightSignalParser (dataprocessing模块)
+
+**职责**: 解析DI格式的红绿灯信号,转换为内部状态枚举
+
+**接口设计**:
+```java
+@Component
+public class TrafficLightSignalParser {
+ // 解析原始JSON信号
+ public TrafficLightStatus parseSignal(String rawJsonSignal);
+
+ // 验证信号格式
+ public boolean isValidSignal(String rawJsonSignal);
+
+ // 获取解析统计信息
+ public ParseStatistics getStatistics();
+}
+```
+
+**信号状态枚举**:
+```java
+public enum SignalState {
+ RED("red"),
+ YELLOW("yellow"),
+ GREEN("green"),
+ UNKNOWN("unknown");
+}
+
+public class TrafficLightStatus {
+ private String deviceId; // 红绿灯设备编号
+ private String intersectionId; // 关联的路口编号
+ private SignalState nsStatus; // 南北方向状态
+ private SignalState ewStatus; // 东西方向状态
+ private long timestamp; // 信号时间戳
+ private String rawSignal; // 原始信号数据(用于调试)
+}
+```
+
+### 6. IntersectionService (新增服务)
+
+**职责**: 管理路口信息,提供路口数据的CRUD操作
+
+**接口设计**:
+```java
+@Service
+public class IntersectionService {
+ // 根据路口编号获取路口信息
+ public Intersection getIntersectionById(String intersectionId);
+
+ // 获取所有激活的路口
+ public List getAllActiveIntersections();
+
+ // 添加新路口
+ public void addIntersection(Intersection intersection);
+
+ // 更新路口信息
+ public void updateIntersection(Intersection intersection);
+}
+```
+
+### 7. TrafficLightService (新增服务)
+
+**职责**: 管理红绿灯设备信息,提供设备数据的CRUD操作
+
+**接口设计**:
+```java
+@Service
+public class TrafficLightService {
+ // 根据设备编号获取红绿灯信息
+ public TrafficLight getTrafficLightByDeviceId(String deviceId);
+
+ // 根据路口编号获取红绿灯设备
+ public List getTrafficLightsByIntersection(String intersectionId);
+
+ // 更新设备在线状态
+ public void updateDeviceOnlineStatus(String deviceId, boolean isOnline);
+
+ // 更新设备心跳时间
+ public void updateDeviceHeartbeat(String deviceId);
+}
+```
+
+**实体类**:
+```java
+@Entity
+@Table(name = "intersections")
+public class Intersection {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "intersection_id", unique = true, nullable = false)
+ private String intersectionId;
+
+ @Column(name = "intersection_name", nullable = false)
+ private String intersectionName;
+
+ @Column(name = "latitude", nullable = false)
+ private Double latitude;
+
+ @Column(name = "longitude", nullable = false)
+ private Double longitude;
+
+ @Column(name = "area_code")
+ private String areaCode;
+
+ @Column(name = "description")
+ private String description;
+
+ @Column(name = "is_active")
+ private Boolean isActive = true;
+
+ // getters and setters...
+}
+
+@Entity
+@Table(name = "traffic_lights")
+public class TrafficLight {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "device_id", unique = true, nullable = false)
+ private String deviceId;
+
+ @Column(name = "device_name", nullable = false)
+ private String deviceName;
+
+ @Column(name = "intersection_id", nullable = false)
+ private String intersectionId;
+
+ @Column(name = "device_type")
+ private String deviceType = "STANDARD";
+
+ @Column(name = "manufacturer")
+ private String manufacturer;
+
+ @Column(name = "model")
+ private String model;
+
+ @Column(name = "install_date")
+ private LocalDate installDate;
+
+ @Column(name = "is_online")
+ private Boolean isOnline = false;
+
+ @Column(name = "last_heartbeat")
+ private LocalDateTime lastHeartbeat;
+
+ @Column(name = "is_active")
+ private Boolean isActive = true;
+
+ // getters and setters...
+}
+```
+
+### 4. DataProcessingService扩展 (dataprocessing模块)
+
+**职责**: 在现有数据处理服务中添加红绿灯数据处理逻辑
+
+**接口扩展**:
+```java
+@Service
+public class DataProcessingService {
+ // 现有方法...
+
+ // 新增:处理红绿灯信号数据
+ public void processTrafficLightSignal(String rawJsonSignal);
+
+ // 创建WebSocket消息载荷(包含路口位置信息)
+ private TrafficLightStatusPayload createTrafficLightPayload(
+ TrafficLightStatus status,
+ TrafficLight device,
+ Intersection intersection
+ );
+
+ // 发布状态变更事件
+ private void publishTrafficLightStatusEvent(TrafficLightStatusPayload payload);
+
+ // 验证设备是否存在和在线
+ private boolean isValidTrafficLightDevice(String deviceId);
+
+ // 更新设备心跳和在线状态
+ private void updateDeviceStatus(String deviceId);
+}
+```
+
+### 5. TrafficLightStatusEventListener (websocket模块)
+
+**职责**: 监听红绿灯状态事件,通过WebSocket广播更新
+
+**接口设计**:
+```java
+@Component
+public class TrafficLightStatusEventListener {
+ // 处理红绿灯状态事件
+ @EventListener
+ public void handleTrafficLightStatusEvent(TrafficLightStatusEvent event);
+
+ // 广播WebSocket消息
+ private void broadcastStatusUpdate(TrafficLightStatusPayload payload);
+}
+```
+
+## 数据模型
+
+### 原始信号格式
+```json
+{
+ "device_id": "TL_001", // 红绿灯设备编号(新增)
+ "DI-01": 0,
+ "DI-02": 0,
+ "DI-11": 1, // 北红
+ "DI-12": 0, // 北黄
+ "DI-13": 0, // 北绿
+ "DI-14": 0, // 东红
+ "DI-15": 0, // 东黄
+ "DI-16": 1, // 东绿
+ "DI-17": 0,
+ "DI-18": 0
+}
+```
+
+### 内部状态模型
+```java
+public class TrafficLightStatus {
+ private SignalState nsStatus; // 南北方向状态
+ private SignalState ewStatus; // 东西方向状态
+ private long timestamp; // 微秒级时间戳
+ private String intersectionId; // 路口标识符
+}
+```
+
+### WebSocket消息格式
+```json
+{
+ "type": "intersection_traffic_light_status",
+ "timestamp": 1704067200000000,
+ "payload": {
+ "intersection_id": "INTERSECTION_001",
+ "intersection_name": "主要路口1号",
+ "device_id": "TL_001",
+ "device_name": "主路口红绿灯1号",
+ "position": {
+ "latitude": 39.9042,
+ "longitude": 116.4074
+ },
+ "ns_status": "red",
+ "ew_status": "green",
+ "timestamp": 1704067200000000,
+ "area_code": "AREA_A"
+ }
+}
+```
+
+## 错误处理
+
+### 1. 网络错误处理
+- **连接断开**: 记录日志,等待客户端重新连接
+- **端口占用**: 尝试备用端口,记录错误信息
+- **网络超时**: 设置合理的超时时间,自动重试机制
+
+### 2. 数据解析错误处理
+- **JSON格式错误**: 记录原始数据,跳过当前消息
+- **DI字段缺失**: 使用默认安全状态(红灯)
+- **无效状态值**: 映射到UNKNOWN状态,记录警告
+
+### 3. 系统错误处理
+- **内存不足**: 限制连接数,清理过期数据
+- **线程池满**: 使用队列缓冲,记录性能指标
+- **WebSocket断开**: 继续处理信号,不影响数据采集
+
+## 测试策略
+
+### 1. 单元测试
+- **信号解析器测试**: 验证各种DI组合的解析结果
+- **状态转换测试**: 验证信号状态到枚举的映射
+- **错误处理测试**: 验证异常情况的处理逻辑
+
+### 2. 集成测试
+- **TCP服务器测试**: 模拟红绿灯硬件连接和数据发送
+- **WebSocket广播测试**: 验证消息格式和广播功能
+- **端到端测试**: 从信号接收到前端显示的完整流程
+
+### 3. 性能测试
+- **高频信号测试**: 验证每秒多次信号的处理能力
+- **并发连接测试**: 验证多个硬件设备同时连接
+- **长时间运行测试**: 验证系统稳定性和内存泄漏
+
+## 配置管理
+
+### 应用配置文件 (application.yml)
+```yaml
+traffic:
+ light:
+ tcp:
+ enabled: true
+ port: 8082
+ max-connections: 50 # 支持更多路口连接
+ connection-timeout: 30000
+ processing:
+ enable-statistics: true
+ statistics-interval: 60000
+ default-intersection:
+ latitude: 0.0 # 默认坐标,实际坐标从数据库获取
+ longitude: 0.0
+```
+
+### 数据库表设计
+
+#### 路口信息表 (intersections)
+```sql
+CREATE TABLE intersections (
+ id BIGSERIAL PRIMARY KEY,
+ intersection_id VARCHAR(50) UNIQUE NOT NULL, -- 路口编号
+ intersection_name VARCHAR(100) NOT NULL, -- 路口名称
+ latitude DECIMAL(10, 8) NOT NULL, -- 纬度
+ longitude DECIMAL(11, 8) NOT NULL, -- 经度
+ area_code VARCHAR(20), -- 区域编码
+ description TEXT, -- 路口描述
+ is_active BOOLEAN DEFAULT true, -- 是否激活
+ created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 创建索引
+CREATE INDEX idx_intersection_id ON intersections(intersection_id);
+CREATE INDEX idx_area_code ON intersections(area_code);
+```
+
+#### 红绿灯设备表 (traffic_lights)
+```sql
+CREATE TABLE traffic_lights (
+ id BIGSERIAL PRIMARY KEY,
+ device_id VARCHAR(50) UNIQUE NOT NULL, -- 红绿灯设备编号
+ device_name VARCHAR(100) NOT NULL, -- 设备名称
+ intersection_id VARCHAR(50) NOT NULL, -- 关联的路口编号
+ device_type VARCHAR(20) DEFAULT 'STANDARD', -- 设备类型
+ manufacturer VARCHAR(50), -- 制造商
+ model VARCHAR(50), -- 型号
+ install_date DATE, -- 安装日期
+ is_online BOOLEAN DEFAULT false, -- 是否在线
+ last_heartbeat TIMESTAMP, -- 最后心跳时间
+ is_active BOOLEAN DEFAULT true, -- 是否激活
+ created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+
+ -- 外键约束
+ CONSTRAINT fk_traffic_light_intersection
+ FOREIGN KEY (intersection_id)
+ REFERENCES intersections(intersection_id)
+);
+
+-- 创建索引
+CREATE INDEX idx_traffic_light_device_id ON traffic_lights(device_id);
+CREATE INDEX idx_traffic_light_intersection ON traffic_lights(intersection_id);
+CREATE INDEX idx_traffic_light_online ON traffic_lights(is_online);
+```
+
+### 日志配置
+- **信号接收日志**: DEBUG级别,记录原始信号数据
+- **解析错误日志**: WARN级别,记录解析失败的信号
+- **系统状态日志**: INFO级别,定期记录处理统计信息
+- **网络错误日志**: ERROR级别,记录连接和网络问题
\ No newline at end of file
diff --git a/.kiro/specs/traffic-light-integration/requirements.md b/.kiro/specs/traffic-light-integration/requirements.md
new file mode 100644
index 00000000..34fa7199
--- /dev/null
+++ b/.kiro/specs/traffic-light-integration/requirements.md
@@ -0,0 +1,71 @@
+# 需求文档
+
+## 介绍
+
+本功能为QAUP机场管理系统实现红绿灯信号接入。系统需要监听来自外部硬件的红绿灯状态信号,解析原始信号数据,转换为内部消息格式,并通过WebSocket向前端客户端广播状态更新。红绿灯信号提供实时路口状态信息,对机场交通管理和碰撞避免至关重要。
+
+## 需求
+
+### 需求 1
+
+**用户故事:** 作为交通控制操作员,我希望系统能够自动接收来自外部硬件的红绿灯信号,以便我能够实时监控路口状态而无需手动干预。
+
+#### 验收标准
+
+1. 当系统启动时,系统应在8082端口建立TCP服务器监听器
+2. 当红绿灯硬件发送状态信号时,系统应接收并捕获原始JSON数据
+3. 当TCP服务器接收到格式错误的数据时,系统应记录错误并继续监听
+4. 当TCP连接遇到网络错误时,系统应自动处理连接断开并等待重新连接
+5. 当系统关闭时,TCP服务器应优雅地关闭所有连接
+
+### 需求 2
+
+**用户故事:** 作为系统管理员,我希望红绿灯信号解析器能够将原始硬件信号转换为标准化的内部格式,以便数据能够被其他系统组件一致地处理。
+
+#### 验收标准
+
+1. 当系统接收到原始红绿灯JSON数据时,系统应正确解析DI信号格式
+2. 当解析DI-11到DI-13信号时,系统应将它们映射到南北方向状态(红/黄/绿)
+3. 当解析DI-14到DI-16信号时,系统应将它们映射到东西方向状态(红/黄/绿)
+4. 当多个方向信号同时激活时,系统应确定正确的信号状态优先级
+5. 当原始数据包含无效DI值时,系统应使用默认安全状态(两个方向都为红灯)
+6. 当由于JSON格式错误导致解析失败时,系统应记录错误并跳过该消息
+
+### 需求 3
+
+**用户故事:** 作为前端开发人员,我希望红绿灯状态更新通过WebSocket以标准UniversalMessage格式广播,以便UI能够与其他系统消息一致地显示实时路口状态。
+
+#### 验收标准
+
+1. 当红绿灯状态改变时,系统应创建包含路口详细信息的TrafficLightStatusPayload
+2. 当发布红绿灯更新时,系统应使用"intersection_traffic_light_status"消息类型
+3. 当通过WebSocket广播时,系统应包含微秒级时间戳
+4. 当未配置路口位置时,系统应使用默认坐标(0.0, 0.0)
+5. 当WebSocket客户端连接时,它们应立即接收红绿灯状态更新
+6. 当没有WebSocket客户端连接时,系统应继续处理信号而不出错
+
+### 需求 4
+
+**用户故事:** 作为系统操作员,我希望红绿灯集成是可配置和可监控的,以便我能够调整设置和排除故障而无需更改代码。
+
+#### 验收标准
+
+1. 当系统启动时,系统应从应用程序属性中读取红绿灯配置
+2. 当配置中禁用红绿灯集成时,UDP监听器不应启动
+3. 当系统处理红绿灯信号时,系统应定期记录处理统计信息
+4. 当信号处理错误发生时,系统应增加错误计数器并记录详细信息
+5. 当未配置路口ID时,系统应使用默认路口标识符
+6. 当TCP端口配置不同时,系统应使用配置的端口而不是8082
+
+### 需求 5
+
+**用户故事:** 作为质量保证工程师,我希望红绿灯集成能够优雅地处理边缘情况和错误条件,以便系统在生产环境中保持稳定和可靠。
+
+#### 验收标准
+
+1. 当TCP端口已被占用时,系统应记录错误并尝试替代端口
+2. 当红绿灯信号接收频率超过1秒间隔时,系统应处理所有信号而不丢失数据
+3. 当重复接收相同信号状态时,系统仍应广播更新以保持客户端同步
+4. 当系统内存不足时,红绿灯处理应以最小内存占用继续运行
+5. 当网络接口不可用时,系统应定期重试连接
+6. 当提供无效路口坐标时,系统应验证并使用安全默认值
\ No newline at end of file
diff --git a/.kiro/specs/traffic-light-integration/tasks.md b/.kiro/specs/traffic-light-integration/tasks.md
new file mode 100644
index 00000000..0ef0661b
--- /dev/null
+++ b/.kiro/specs/traffic-light-integration/tasks.md
@@ -0,0 +1,87 @@
+# 实现计划
+
+- [x] 1. 创建数据库表和实体类
+ - 创建路口信息表(intersections)和红绿灯设备表(traffic_lights)的SQL脚本
+ - 实现Intersection和TrafficLight实体类,包含JPA注解
+ - 创建对应的Repository接口,继承JpaRepository
+ - _需求: 1.1, 4.5, 4.6_
+
+- [x] 2. 实现红绿灯信号解析器
+ - 创建SignalState枚举类,定义红绿灯状态(RED/YELLOW/GREEN/UNKNOWN)
+ - 实现TrafficLightStatus数据模型类,包含设备ID、路口ID、状态等字段
+ - 实现TrafficLightSignalParser类,解析DI格式JSON信号为内部状态
+ - 编写信号解析的单元测试,覆盖正常和异常情况
+ - _需求: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6_
+
+- [x] 3. 实现路口和设备管理服务
+ - 创建IntersectionService类,提供路口信息的CRUD操作
+ - 创建TrafficLightService类,提供红绿灯设备的管理功能
+ - 实现设备在线状态和心跳时间的更新方法
+ - 编写服务层的单元测试
+ - _需求: 4.1, 4.5, 5.5_
+
+- [x] 4. 实现TCP服务器监听红绿灯信号
+ - 创建TrafficLightTcpServer类,使用Java NIO实现TCP服务器
+ - 实现多客户端连接处理,支持并发连接
+ - 添加连接管理功能,包括连接建立、断开和重连处理
+ - 集成Spring配置,支持端口、最大连接数等参数配置
+ - 编写TCP服务器的集成测试
+ - _需求: 1.1, 1.2, 1.4, 1.5, 4.2, 4.6, 5.1_
+
+- [x] 5. 实现数据采集器集成TCP服务器
+ - 创建TrafficLightDataCollector类,集成到现有数据采集框架
+ - 实现TCP服务器接收到信号后的数据传递机制
+ - 添加数据采集统计功能,记录接收信号数量和错误次数
+ - 集成到DataCollectorService的定时任务中
+ - _需求: 1.2, 1.3, 4.3, 4.4_
+
+- [x] 6. 扩展数据处理服务处理红绿灯信号
+ - 在DataProcessingService中添加processTrafficLightSignal方法
+ - 实现设备验证逻辑,检查设备是否存在和激活
+ - 实现路口信息查询,获取位置坐标等信息
+ - 创建TrafficLightStatusPayload,包含完整的路口和设备信息
+ - 更新设备心跳时间和在线状态
+ - _需求: 2.1, 2.4, 2.5, 5.4, 5.6_
+
+- [x] 7. 实现WebSocket事件发布和广播
+ - 扩展现有TrafficLightStatusEvent,支持新的数据结构
+ - 在数据处理服务中发布红绿灯状态变更事件
+ - 创建或更新TrafficLightStatusEventListener,处理事件广播
+ - 确保WebSocket消息格式符合前端要求
+ - _需求: 3.1, 3.2, 3.3, 3.5, 3.6_
+
+- [x] 8. 添加配置管理和错误处理
+ - 在application.yml中添加红绿灯相关配置项
+ - 实现配置类TrafficLightProperties,绑定配置属性
+ - 添加全局异常处理,处理TCP连接、解析错误等异常
+ - 实现优雅关闭机制,确保TCP服务器正确关闭
+ - _需求: 4.1, 4.2, 4.3, 4.4, 5.1, 5.2, 5.3_
+
+- [x] 9. 实现数据库初始化和管理接口
+ - 创建数据库迁移脚本,初始化路口和设备表
+ - 实现路口管理的REST API,支持路口信息的增删改查
+ - 实现设备管理的REST API,支持设备信息的管理
+ - 添加数据验证和约束检查
+ - _需求: 4.5, 4.6, 5.6_
+
+- [x] 10. 编写集成测试和端到端测试
+ - 创建模拟红绿灯硬件的测试客户端
+ - 编写TCP服务器到WebSocket广播的端到端测试
+ - 测试多设备并发连接和信号处理
+ - 测试异常情况处理,如网络断开、格式错误等
+ - 验证性能指标,确保满足每秒信号处理要求
+ - _需求: 1.3, 1.4, 2.6, 5.1, 5.2, 5.3, 5.4_
+
+- [x] 11. 添加监控和日志记录
+ - 实现处理统计功能,记录信号接收和处理数量
+ - 添加性能监控,记录处理延迟和错误率
+ - 配置日志级别,确保调试和生产环境的日志合理
+ - 实现健康检查接口,监控TCP服务器和处理服务状态
+ - _需求: 4.3, 4.4, 5.4_
+
+- [x] 12. 系统集成和部署准备
+ - 将所有组件集成到现有Spring Boot应用中
+ - 更新Docker配置,确保TCP端口正确暴露
+ - 编写部署文档,说明配置和启动步骤
+ - 进行系统级测试,验证与现有功能的兼容性
+ - _需求: 1.5, 4.1, 4.2_
\ No newline at end of file
diff --git a/doc/requirement/requirements.md b/doc/requirement/requirements.md
index 11b96b7a..b73c1808 100644
--- a/doc/requirement/requirements.md
+++ b/doc/requirement/requirements.md
@@ -2,6 +2,16 @@
## 需求列表(按时间跟踪)
+### 2025-08-05
+
+- 需求:红绿灯信号信息接入
+- 分析:需要监听并解析红绿灯信号,然后传送给前端
+- 功能模块:
+ - 数据采集模块:监听接收红绿灯信号
+ - 数据处理模块:解析红绿灯信号
+ - 通信模块:将红绿灯信号发送给前端
+ - 前端展示模块:对红绿灯信号信息进行展示
+
### 2025-07-03
- 需求:航空器路由信息接入
diff --git a/doc/requirement/traffic_light_request.md b/doc/requirement/traffic_light_request.md
new file mode 100644
index 00000000..f6baea4c
--- /dev/null
+++ b/doc/requirement/traffic_light_request.md
@@ -0,0 +1,15 @@
+- 红绿灯状态上报消息格式:
+
+```
+{"DI-01":0,"DI-02":0,"DI-11":1,"DI-12":0,"DI-13":0,"DI-14":0,"DI-15":0,"DI-16":1,"DI-17":0,"DI-18":0}
+```
+
+- 其中:DI-11~13 表示南北向灯的状态,DI14~16 表示东西向灯
+
+DI-11":北红,"DI-12":北黄,"DI-13":北绿,"DI-14":东红,"DI-15":东黄,"DI-16":东绿
+
+- 只有包含 DI 的这一段有用,其他的都是 0
+
+- 红绿灯状态上报频率:每 1 秒上报一次
+
+- 红绿灯状态上报端口:8082
diff --git a/doc/traffic-light-deployment.md b/doc/traffic-light-deployment.md
new file mode 100644
index 00000000..d567079b
--- /dev/null
+++ b/doc/traffic-light-deployment.md
@@ -0,0 +1,352 @@
+# 红绿灯信号集成系统部署指南
+
+## 概述
+
+本文档描述了红绿灯信号集成系统的部署步骤和配置说明。该系统通过TCP服务器接收红绿灯硬件信号,解析后通过WebSocket广播给前端客户端。
+
+## 系统架构
+
+```
+红绿灯硬件 → TCP服务器(8082) → 信号解析器 → 数据处理服务 → WebSocket广播 → 前端客户端
+ ↓
+ 数据库(路口/设备管理)
+```
+
+## 部署前准备
+
+### 1. 环境要求
+
+- **Java**: JDK 17 或更高版本
+- **数据库**: PostgreSQL 12+ (已启用PostGIS扩展)
+- **Redis**: 6.0+ (用于缓存)
+- **网络**: 确保8082端口可用于TCP连接
+
+### 2. 数据库初始化
+
+执行以下SQL脚本初始化红绿灯相关表:
+
+```bash
+# 1. 创建红绿灯系统表
+psql -h localhost -U postgres -d qaup_database -f sql/create_traffic_light_tables.sql
+
+# 2. 验证数据完整性
+psql -h localhost -U postgres -d qaup_database -f sql/validate_traffic_light_data.sql
+```
+
+### 3. 配置文件设置
+
+在 `application.yml` 中配置红绿灯系统参数:
+
+```yaml
+# 红绿灯系统配置
+traffic:
+ light:
+ tcp:
+ # 是否启用TCP服务器
+ enabled: true
+ # TCP监听端口
+ port: 8082
+ # 最大连接数
+ max-connections: 50
+ # 连接超时时间(毫秒)
+ connection-timeout: 30000
+ # 心跳超时时间(分钟)
+ heartbeat-timeout-minutes: 5
+
+ intersection:
+ # 默认路口ID(当信号中没有指定时使用)
+ default-id: "DEFAULT_INTERSECTION"
+ # 默认坐标
+ default-latitude: 0.0
+ default-longitude: 0.0
+
+ processing:
+ # 是否启用统计功能
+ enable-statistics: true
+ # 统计信息输出间隔(毫秒)
+ statistics-interval: 60000
+ # 是否启用调试日志
+ enable-debug-log: false
+```
+
+## 部署步骤
+
+### 1. 编译和打包
+
+```bash
+# 编译项目
+mvn clean compile
+
+# 运行测试
+mvn test
+
+# 打包应用
+mvn clean package -DskipTests
+```
+
+### 2. 启动应用
+
+```bash
+# 方式1: 直接运行JAR包
+java -jar qaup-admin/target/qaup-admin.jar
+
+# 方式2: 使用Spring Boot Maven插件
+mvn spring-boot:run -pl qaup-admin
+
+# 方式3: 使用Docker (如果有Docker配置)
+docker-compose up -d
+```
+
+### 3. 验证部署
+
+#### 检查TCP服务器状态
+```bash
+# 检查端口是否监听
+netstat -tlnp | grep 8082
+
+# 或使用ss命令
+ss -tlnp | grep 8082
+```
+
+#### 检查应用健康状态
+```bash
+# 访问健康检查接口
+curl http://localhost:8080/health
+
+# 检查红绿灯系统状态
+curl http://localhost:8080/health/traffic-light
+```
+
+#### 检查WebSocket连接
+```bash
+# 访问WebSocket测试页面
+http://localhost:8080/websocket-test.html
+```
+
+## 配置管理
+
+### 1. 路口信息管理
+
+通过REST API管理路口信息:
+
+```bash
+# 查看所有路口
+curl http://localhost:8080/api/intersections
+
+# 添加新路口
+curl -X POST http://localhost:8080/api/intersections \
+ -H "Content-Type: application/json" \
+ -d '{
+ "intersectionId": "INTERSECTION_003",
+ "intersectionName": "新路口",
+ "latitude": 39.9060,
+ "longitude": 116.4090,
+ "areaCode": "AREA_C"
+ }'
+
+# 查看特定路口
+curl http://localhost:8080/api/intersections/INTERSECTION_001
+```
+
+### 2. 红绿灯设备管理
+
+```bash
+# 查看所有设备
+curl http://localhost:8080/api/traffic-lights
+
+# 添加新设备
+curl -X POST http://localhost:8080/api/traffic-lights \
+ -H "Content-Type: application/json" \
+ -d '{
+ "deviceId": "TL_003",
+ "deviceName": "新红绿灯设备",
+ "intersectionId": "INTERSECTION_003",
+ "manufacturer": "海康威视",
+ "model": "DS-TL300"
+ }'
+
+# 查看设备状态
+curl http://localhost:8080/api/traffic-lights/TL_001/status
+```
+
+## 测试和验证
+
+### 1. 使用测试客户端
+
+运行提供的Python测试客户端:
+
+```bash
+# 安装Python依赖(如果需要)
+pip3 install socket json
+
+# 运行测试客户端
+python3 test_traffic_light_client.py
+```
+
+### 2. 手动发送测试信号
+
+使用telnet或nc命令手动发送信号:
+
+```bash
+# 使用telnet
+telnet localhost 8082
+
+# 发送JSON信号(在telnet会话中)
+{"device_id":"TL_001","DI-01":0,"DI-02":0,"DI-11":1,"DI-12":0,"DI-13":0,"DI-14":0,"DI-15":0,"DI-16":1,"DI-17":0,"DI-18":0}
+
+# 使用nc命令
+echo '{"device_id":"TL_001","DI-11":1,"DI-16":1}' | nc localhost 8082
+```
+
+### 3. 监控WebSocket消息
+
+在浏览器中打开开发者工具,连接到WebSocket端点:
+
+```javascript
+const ws = new WebSocket('ws://localhost:8080/collision');
+ws.onmessage = function(event) {
+ const message = JSON.parse(event.data);
+ if (message.type === 'intersection_traffic_light_status') {
+ console.log('红绿灯状态更新:', message.payload);
+ }
+};
+```
+
+## 故障排除
+
+### 1. TCP服务器无法启动
+
+**问题**: 端口8082被占用
+```bash
+# 查找占用端口的进程
+lsof -i :8082
+
+# 杀死占用进程
+kill -9
+```
+
+**问题**: 权限不足
+```bash
+# 使用sudo运行或更改端口到1024以上
+```
+
+### 2. 数据库连接问题
+
+**问题**: 无法连接到PostgreSQL
+```bash
+# 检查数据库服务状态
+systemctl status postgresql
+
+# 检查连接配置
+psql -h localhost -U postgres -d qaup_database -c "SELECT 1;"
+```
+
+### 3. 信号解析错误
+
+**问题**: JSON格式错误
+- 检查发送的JSON格式是否正确
+- 查看应用日志中的解析错误信息
+- 使用JSON验证工具验证格式
+
+### 4. WebSocket连接问题
+
+**问题**: 前端无法接收消息
+- 检查WebSocket连接是否建立成功
+- 验证消息类型过滤是否正确
+- 查看浏览器控制台错误信息
+
+## 性能监控
+
+### 1. 关键指标
+
+- **TCP连接数**: 当前活跃的红绿灯设备连接数
+- **信号处理速度**: 每秒处理的信号数量
+- **解析成功率**: 成功解析的信号比例
+- **WebSocket客户端数**: 连接的前端客户端数量
+
+### 2. 监控接口
+
+```bash
+# 系统整体状态
+curl http://localhost:8080/health
+
+# 红绿灯系统统计
+curl http://localhost:8080/api/traffic-lights/statistics
+
+# TCP服务器状态
+curl http://localhost:8080/api/traffic-lights/server/status
+```
+
+### 3. 日志监控
+
+重要日志文件和关键字:
+
+```bash
+# 查看TCP服务器日志
+grep "TrafficLightTcpServer" logs/application.log
+
+# 查看信号解析日志
+grep "TrafficLightSignalParser" logs/application.log
+
+# 查看WebSocket广播日志
+grep "TrafficLightStatusEventListener" logs/application.log
+```
+
+## 安全考虑
+
+### 1. 网络安全
+
+- 限制8082端口的访问来源
+- 使用防火墙规则保护TCP端口
+- 考虑使用TLS加密TCP连接(如果硬件支持)
+
+### 2. 数据验证
+
+- 验证设备ID的合法性
+- 检查信号数据的合理性
+- 记录异常信号和可疑连接
+
+### 3. 访问控制
+
+- 为管理API添加认证机制
+- 限制WebSocket连接的来源
+- 定期审查设备注册信息
+
+## 维护和升级
+
+### 1. 定期维护
+
+- 清理过期的连接记录
+- 检查数据库表的性能
+- 更新设备心跳状态
+- 备份路口和设备配置
+
+### 2. 系统升级
+
+- 在升级前备份数据库
+- 测试新版本的兼容性
+- 逐步升级,避免服务中断
+- 验证升级后的功能完整性
+
+### 3. 容量规划
+
+- 监控系统资源使用情况
+- 根据设备数量调整连接池大小
+- 优化数据库查询性能
+- 考虑水平扩展方案
+
+## 联系支持
+
+如遇到部署问题,请提供以下信息:
+
+1. 系统环境信息(OS、Java版本等)
+2. 错误日志和堆栈跟踪
+3. 配置文件内容
+4. 网络环境描述
+5. 复现步骤
+
+---
+
+**版本**: 1.0.0
+**更新日期**: 2025-01-05
+**维护团队**: QAUP开发团队
\ No newline at end of file
diff --git a/qaup-admin/src/main/resources/application.yml b/qaup-admin/src/main/resources/application.yml
index f9346b32..5aaabfb4 100644
--- a/qaup-admin/src/main/resources/application.yml
+++ b/qaup-admin/src/main/resources/application.yml
@@ -36,6 +36,12 @@ logging:
level:
com.qaup: debug
org.springframework: warn
+ # 红绿灯系统日志级别
+ com.qaup.collision.datacollector.server: INFO
+ com.qaup.collision.datacollector.service.TrafficLightDataCollector: INFO
+ com.qaup.collision.dataprocessing.parser.TrafficLightSignalParser: INFO
+ com.qaup.collision.dataprocessing.service.TrafficLightService: INFO
+ com.qaup.collision.dataprocessing.service.IntersectionService: INFO
# 用户配置
user:
@@ -227,6 +233,39 @@ data:
redis-expire-seconds: 60
postgresql-days: 30
+# 红绿灯系统配置(collision模块)
+traffic:
+ light:
+ tcp:
+ # 是否启用TCP服务器
+ enabled: true
+ # TCP监听端口
+ port: 8082
+ # 最大连接数
+ max-connections: 50
+ # 连接超时时间(毫秒)
+ connection-timeout: 30000
+ # 心跳超时时间(分钟)
+ heartbeat-timeout-minutes: 5
+
+ intersection:
+ # 默认路口ID(当信号中没有指定时使用)
+ default-id: "DEFAULT_INTERSECTION"
+ # 默认纬度坐标
+ default-latitude: 0.0
+ # 默认经度坐标
+ default-longitude: 0.0
+
+ processing:
+ # 是否启用统计功能
+ enable-statistics: true
+ # 统计信息输出间隔(毫秒)
+ statistics-interval: 60000
+ # 是否启用调试日志
+ enable-debug-log: false
+ # 信号处理超时时间(毫秒)
+ signal-process-timeout: 5000
+
# 坐标系统配置(collision模块)
coordinate-system:
airport:
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/exception/DeviceNotFoundException.java b/qaup-collision/src/main/java/com/qaup/collision/common/exception/DeviceNotFoundException.java
new file mode 100644
index 00000000..9f54400c
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/exception/DeviceNotFoundException.java
@@ -0,0 +1,21 @@
+package com.qaup.collision.common.exception;
+
+/**
+ * 设备不存在异常
+ *
+ * 用于表示红绿灯设备不存在的异常
+ */
+public class DeviceNotFoundException extends RuntimeException {
+
+ public DeviceNotFoundException(String message) {
+ super(message);
+ }
+
+ public DeviceNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public DeviceNotFoundException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/exception/IntersectionNotFoundException.java b/qaup-collision/src/main/java/com/qaup/collision/common/exception/IntersectionNotFoundException.java
new file mode 100644
index 00000000..857116fc
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/exception/IntersectionNotFoundException.java
@@ -0,0 +1,21 @@
+package com.qaup.collision.common.exception;
+
+/**
+ * 路口不存在异常
+ *
+ * 用于表示路口不存在的异常
+ */
+public class IntersectionNotFoundException extends RuntimeException {
+
+ public IntersectionNotFoundException(String message) {
+ super(message);
+ }
+
+ public IntersectionNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public IntersectionNotFoundException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/exception/SignalParsingException.java b/qaup-collision/src/main/java/com/qaup/collision/common/exception/SignalParsingException.java
new file mode 100644
index 00000000..244f6817
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/exception/SignalParsingException.java
@@ -0,0 +1,21 @@
+package com.qaup.collision.common.exception;
+
+/**
+ * 信号解析异常
+ *
+ * 用于表示红绿灯信号解析过程中的异常
+ */
+public class SignalParsingException extends RuntimeException {
+
+ public SignalParsingException(String message) {
+ super(message);
+ }
+
+ public SignalParsingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SignalParsingException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/exception/TcpConnectionException.java b/qaup-collision/src/main/java/com/qaup/collision/common/exception/TcpConnectionException.java
new file mode 100644
index 00000000..a7589bcd
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/exception/TcpConnectionException.java
@@ -0,0 +1,21 @@
+package com.qaup.collision.common.exception;
+
+/**
+ * TCP连接异常
+ *
+ * 用于表示TCP连接相关的异常
+ */
+public class TcpConnectionException extends RuntimeException {
+
+ public TcpConnectionException(String message) {
+ super(message);
+ }
+
+ public TcpConnectionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TcpConnectionException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/exception/TrafficLightException.java b/qaup-collision/src/main/java/com/qaup/collision/common/exception/TrafficLightException.java
new file mode 100644
index 00000000..603f448d
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/exception/TrafficLightException.java
@@ -0,0 +1,21 @@
+package com.qaup.collision.common.exception;
+
+/**
+ * 红绿灯系统异常
+ *
+ * 用于表示红绿灯系统相关的业务异常
+ */
+public class TrafficLightException extends RuntimeException {
+
+ public TrafficLightException(String message) {
+ super(message);
+ }
+
+ public TrafficLightException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TrafficLightException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/model/enums/SignalState.java b/qaup-collision/src/main/java/com/qaup/collision/common/model/enums/SignalState.java
new file mode 100644
index 00000000..62aaf659
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/model/enums/SignalState.java
@@ -0,0 +1,118 @@
+package com.qaup.collision.common.model.enums;
+
+/**
+ * 红绿灯信号状态枚举
+ *
+ * 定义红绿灯的四种基本状态,用于统一系统内的信号状态表示
+ */
+public enum SignalState {
+
+ /**
+ * 红灯状态
+ */
+ RED("red", "红灯"),
+
+ /**
+ * 黄灯状态
+ */
+ YELLOW("yellow", "黄灯"),
+
+ /**
+ * 绿灯状态
+ */
+ GREEN("green", "绿灯"),
+
+ /**
+ * 未知状态(用于异常情况或初始化)
+ */
+ UNKNOWN("unknown", "未知");
+
+ private final String code;
+ private final String description;
+
+ SignalState(String code, String description) {
+ this.code = code;
+ this.description = description;
+ }
+
+ /**
+ * 获取状态编码
+ *
+ * @return 状态编码字符串
+ */
+ public String getCode() {
+ return code;
+ }
+
+ /**
+ * 获取状态描述
+ *
+ * @return 状态描述字符串
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * 根据编码获取信号状态
+ *
+ * @param code 状态编码
+ * @return 对应的信号状态,如果找不到则返回UNKNOWN
+ */
+ public static SignalState fromCode(String code) {
+ if (code == null) {
+ return UNKNOWN;
+ }
+
+ for (SignalState state : values()) {
+ if (state.code.equalsIgnoreCase(code)) {
+ return state;
+ }
+ }
+
+ return UNKNOWN;
+ }
+
+ /**
+ * 检查是否为安全状态(红灯或黄灯)
+ *
+ * @return true如果是安全状态,false否则
+ */
+ public boolean isSafeState() {
+ return this == RED || this == YELLOW;
+ }
+
+ /**
+ * 检查是否为通行状态(绿灯)
+ *
+ * @return true如果是通行状态,false否则
+ */
+ public boolean isPassState() {
+ return this == GREEN;
+ }
+
+ /**
+ * 获取优先级(用于多信号同时激活时的状态判断)
+ * 红灯优先级最高,绿灯最低
+ *
+ * @return 优先级数值,数值越小优先级越高
+ */
+ public int getPriority() {
+ switch (this) {
+ case RED:
+ return 1;
+ case YELLOW:
+ return 2;
+ case GREEN:
+ return 3;
+ case UNKNOWN:
+ default:
+ return 4;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return code;
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/model/repository/IntersectionRepository.java b/qaup-collision/src/main/java/com/qaup/collision/common/model/repository/IntersectionRepository.java
new file mode 100644
index 00000000..9780c89d
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/model/repository/IntersectionRepository.java
@@ -0,0 +1,109 @@
+package com.qaup.collision.common.model.repository;
+
+import com.qaup.collision.common.model.spatial.Intersection;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 路口信息Repository接口
+ *
+ * 提供路口信息的数据访问操作,包括基本的CRUD和业务查询方法
+ */
+@Repository
+public interface IntersectionRepository extends JpaRepository {
+
+ /**
+ * 根据路口编号查找路口
+ *
+ * @param intersectionId 路口编号
+ * @return 路口信息(可选)
+ */
+ Optional findByIntersectionId(String intersectionId);
+
+ /**
+ * 根据路口编号和激活状态查找路口
+ *
+ * @param intersectionId 路口编号
+ * @param isActive 是否激活
+ * @return 路口信息(可选)
+ */
+ Optional findByIntersectionIdAndIsActive(String intersectionId, Boolean isActive);
+
+ /**
+ * 查找所有激活的路口
+ *
+ * @return 激活的路口列表
+ */
+ List findByIsActiveTrue();
+
+ /**
+ * 根据区域编码查找路口
+ *
+ * @param areaCode 区域编码
+ * @return 该区域的路口列表
+ */
+ List findByAreaCode(String areaCode);
+
+ /**
+ * 根据区域编码查找激活的路口
+ *
+ * @param areaCode 区域编码
+ * @return 该区域激活的路口列表
+ */
+ List findByAreaCodeAndIsActiveTrue(String areaCode);
+
+ /**
+ * 检查路口编号是否存在
+ *
+ * @param intersectionId 路口编号
+ * @return true如果存在,false否则
+ */
+ boolean existsByIntersectionId(String intersectionId);
+
+ /**
+ * 根据路口名称模糊查询
+ *
+ * @param name 路口名称关键字
+ * @return 匹配的路口列表
+ */
+ @Query("SELECT i FROM Intersection i WHERE i.intersectionName LIKE %:name%")
+ List findByIntersectionNameContaining(@Param("name") String name);
+
+ /**
+ * 根据坐标范围查找路口
+ *
+ * @param minLat 最小纬度
+ * @param maxLat 最大纬度
+ * @param minLng 最小经度
+ * @param maxLng 最大经度
+ * @return 范围内的路口列表
+ */
+ @Query("SELECT i FROM Intersection i WHERE i.latitude BETWEEN :minLat AND :maxLat " +
+ "AND i.longitude BETWEEN :minLng AND :maxLng AND i.isActive = true")
+ List findIntersectionsInBounds(
+ @Param("minLat") Double minLat,
+ @Param("maxLat") Double maxLat,
+ @Param("minLng") Double minLng,
+ @Param("maxLng") Double maxLng
+ );
+
+ /**
+ * 统计激活的路口数量
+ *
+ * @return 激活路口数量
+ */
+ long countByIsActiveTrue();
+
+ /**
+ * 根据区域编码统计路口数量
+ *
+ * @param areaCode 区域编码
+ * @return 该区域的路口数量
+ */
+ long countByAreaCode(String areaCode);
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/model/repository/TrafficLightRepository.java b/qaup-collision/src/main/java/com/qaup/collision/common/model/repository/TrafficLightRepository.java
new file mode 100644
index 00000000..4d2d9507
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/model/repository/TrafficLightRepository.java
@@ -0,0 +1,168 @@
+package com.qaup.collision.common.model.repository;
+
+import com.qaup.collision.common.model.spatial.TrafficLight;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 红绿灯设备Repository接口
+ *
+ * 提供红绿灯设备的数据访问操作,包括基本的CRUD和业务查询方法
+ */
+@Repository
+public interface TrafficLightRepository extends JpaRepository {
+
+ /**
+ * 根据设备编号查找红绿灯设备
+ *
+ * @param deviceId 设备编号
+ * @return 红绿灯设备信息(可选)
+ */
+ Optional findByDeviceId(String deviceId);
+
+ /**
+ * 根据设备编号和激活状态查找设备
+ *
+ * @param deviceId 设备编号
+ * @param isActive 是否激活
+ * @return 红绿灯设备信息(可选)
+ */
+ Optional findByDeviceIdAndIsActive(String deviceId, Boolean isActive);
+
+ /**
+ * 根据路口编号查找所有红绿灯设备
+ *
+ * @param intersectionId 路口编号
+ * @return 该路口的红绿灯设备列表
+ */
+ List findByIntersectionId(String intersectionId);
+
+ /**
+ * 根据路口编号查找激活的红绿灯设备
+ *
+ * @param intersectionId 路口编号
+ * @return 该路口激活的红绿灯设备列表
+ */
+ List findByIntersectionIdAndIsActiveTrue(String intersectionId);
+
+ /**
+ * 查找所有在线的设备
+ *
+ * @return 在线设备列表
+ */
+ List findByIsOnlineTrue();
+
+ /**
+ * 查找所有激活且在线的设备
+ *
+ * @return 激活且在线的设备列表
+ */
+ List findByIsActiveTrueAndIsOnlineTrue();
+
+ /**
+ * 检查设备编号是否存在
+ *
+ * @param deviceId 设备编号
+ * @return true如果存在,false否则
+ */
+ boolean existsByDeviceId(String deviceId);
+
+ /**
+ * 根据制造商查找设备
+ *
+ * @param manufacturer 制造商
+ * @return 该制造商的设备列表
+ */
+ List findByManufacturer(String manufacturer);
+
+ /**
+ * 根据设备类型查找设备
+ *
+ * @param deviceType 设备类型
+ * @return 该类型的设备列表
+ */
+ List findByDeviceType(String deviceType);
+
+ /**
+ * 更新设备在线状态
+ *
+ * @param deviceId 设备编号
+ * @param isOnline 是否在线
+ * @return 更新的记录数
+ */
+ @Modifying
+ @Transactional
+ @Query("UPDATE TrafficLight t SET t.isOnline = :isOnline, t.updatedTime = CURRENT_TIMESTAMP WHERE t.deviceId = :deviceId")
+ int updateOnlineStatus(@Param("deviceId") String deviceId, @Param("isOnline") Boolean isOnline);
+
+ /**
+ * 更新设备心跳时间
+ *
+ * @param deviceId 设备编号
+ * @param heartbeatTime 心跳时间
+ * @return 更新的记录数
+ */
+ @Modifying
+ @Transactional
+ @Query("UPDATE TrafficLight t SET t.lastHeartbeat = :heartbeatTime, t.isOnline = true, t.updatedTime = CURRENT_TIMESTAMP WHERE t.deviceId = :deviceId")
+ int updateHeartbeat(@Param("deviceId") String deviceId, @Param("heartbeatTime") LocalDateTime heartbeatTime);
+
+ /**
+ * 查找心跳超时的设备
+ *
+ * @param timeoutTime 超时时间点
+ * @return 心跳超时的设备列表
+ */
+ @Query("SELECT t FROM TrafficLight t WHERE t.isOnline = true AND (t.lastHeartbeat IS NULL OR t.lastHeartbeat < :timeoutTime)")
+ List findHeartbeatTimeoutDevices(@Param("timeoutTime") LocalDateTime timeoutTime);
+
+ /**
+ * 批量设置心跳超时设备为离线状态
+ *
+ * @param timeoutTime 超时时间点
+ * @return 更新的记录数
+ */
+ @Modifying
+ @Transactional
+ @Query("UPDATE TrafficLight t SET t.isOnline = false, t.updatedTime = CURRENT_TIMESTAMP WHERE t.isOnline = true AND (t.lastHeartbeat IS NULL OR t.lastHeartbeat < :timeoutTime)")
+ int setTimeoutDevicesOffline(@Param("timeoutTime") LocalDateTime timeoutTime);
+
+ /**
+ * 统计在线设备数量
+ *
+ * @return 在线设备数量
+ */
+ long countByIsOnlineTrue();
+
+ /**
+ * 统计激活设备数量
+ *
+ * @return 激活设备数量
+ */
+ long countByIsActiveTrue();
+
+ /**
+ * 根据路口编号统计设备数量
+ *
+ * @param intersectionId 路口编号
+ * @return 该路口的设备数量
+ */
+ long countByIntersectionId(String intersectionId);
+
+ /**
+ * 根据设备名称模糊查询
+ *
+ * @param name 设备名称关键字
+ * @return 匹配的设备列表
+ */
+ @Query("SELECT t FROM TrafficLight t WHERE t.deviceName LIKE %:name%")
+ List findByDeviceNameContaining(@Param("name") String name);
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/model/spatial/Intersection.java b/qaup-collision/src/main/java/com/qaup/collision/common/model/spatial/Intersection.java
new file mode 100644
index 00000000..87c96b9e
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/model/spatial/Intersection.java
@@ -0,0 +1,116 @@
+package com.qaup.collision.common.model.spatial;
+
+import jakarta.persistence.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+
+import java.time.LocalDateTime;
+
+/**
+ * 路口信息实体类
+ *
+ * 用于存储机场内各个路口的基本信息,包括位置坐标、区域归属等
+ * 路口是红绿灯设备的载体,一个路口可以有多个红绿灯设备
+ */
+@Entity
+@Table(name = "intersections")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class Intersection {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ /**
+ * 路口唯一编号
+ */
+ @Column(name = "intersection_id", unique = true, nullable = false, length = 50)
+ private String intersectionId;
+
+ /**
+ * 路口名称
+ */
+ @Column(name = "intersection_name", nullable = false, length = 100)
+ private String intersectionName;
+
+ /**
+ * 纬度坐标
+ */
+ @Column(name = "latitude", nullable = false)
+ private Double latitude;
+
+ /**
+ * 经度坐标
+ */
+ @Column(name = "longitude", nullable = false)
+ private Double longitude;
+
+ /**
+ * 所属区域编码
+ */
+ @Column(name = "area_code", length = 20)
+ private String areaCode;
+
+ /**
+ * 路口描述
+ */
+ @Column(name = "description", columnDefinition = "TEXT")
+ private String description;
+
+ /**
+ * 是否激活
+ */
+ @Column(name = "is_active")
+ @Builder.Default
+ private Boolean isActive = true;
+
+ /**
+ * 创建时间
+ */
+ @Column(name = "created_time")
+ private LocalDateTime createdTime;
+
+ /**
+ * 更新时间
+ */
+ @Column(name = "updated_time")
+ private LocalDateTime updatedTime;
+
+ /**
+ * 预设置创建和更新时间
+ */
+ @PrePersist
+ protected void onCreate() {
+ LocalDateTime now = LocalDateTime.now();
+ createdTime = now;
+ updatedTime = now;
+ }
+
+ @PreUpdate
+ protected void onUpdate() {
+ updatedTime = LocalDateTime.now();
+ }
+
+ /**
+ * 获取路口位置的字符串表示
+ *
+ * @return 格式化的位置字符串
+ */
+ public String getLocationString() {
+ return String.format("%.6f,%.6f", latitude, longitude);
+ }
+
+ /**
+ * 检查路口是否可用(激活状态)
+ *
+ * @return true如果路口激活,false否则
+ */
+ public boolean isAvailable() {
+ return Boolean.TRUE.equals(isActive);
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/model/spatial/TrafficLight.java b/qaup-collision/src/main/java/com/qaup/collision/common/model/spatial/TrafficLight.java
new file mode 100644
index 00000000..d180001c
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/common/model/spatial/TrafficLight.java
@@ -0,0 +1,178 @@
+package com.qaup.collision.common.model.spatial;
+
+import jakarta.persistence.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * 红绿灯设备实体类
+ *
+ * 用于存储红绿灯设备的基本信息,包括设备编号、名称、关联路口等
+ * 每个设备通过intersection_id与路口建立关联关系
+ */
+@Entity
+@Table(name = "traffic_lights")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TrafficLight {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ /**
+ * 红绿灯设备唯一编号
+ */
+ @Column(name = "device_id", unique = true, nullable = false, length = 50)
+ private String deviceId;
+
+ /**
+ * 设备名称
+ */
+ @Column(name = "device_name", nullable = false, length = 100)
+ private String deviceName;
+
+ /**
+ * 关联的路口编号
+ */
+ @Column(name = "intersection_id", nullable = false, length = 50)
+ private String intersectionId;
+
+ /**
+ * 设备类型
+ */
+ @Column(name = "device_type", length = 20)
+ @Builder.Default
+ private String deviceType = "STANDARD";
+
+ /**
+ * 制造商
+ */
+ @Column(name = "manufacturer", length = 50)
+ private String manufacturer;
+
+ /**
+ * 型号
+ */
+ @Column(name = "model", length = 50)
+ private String model;
+
+ /**
+ * 安装日期
+ */
+ @Column(name = "install_date")
+ private LocalDate installDate;
+
+ /**
+ * 是否在线
+ */
+ @Column(name = "is_online")
+ @Builder.Default
+ private Boolean isOnline = false;
+
+ /**
+ * 最后心跳时间
+ */
+ @Column(name = "last_heartbeat")
+ private LocalDateTime lastHeartbeat;
+
+ /**
+ * 是否激活
+ */
+ @Column(name = "is_active")
+ @Builder.Default
+ private Boolean isActive = true;
+
+ /**
+ * 创建时间
+ */
+ @Column(name = "created_time")
+ private LocalDateTime createdTime;
+
+ /**
+ * 更新时间
+ */
+ @Column(name = "updated_time")
+ private LocalDateTime updatedTime;
+
+ /**
+ * 预设置创建和更新时间
+ */
+ @PrePersist
+ protected void onCreate() {
+ LocalDateTime now = LocalDateTime.now();
+ createdTime = now;
+ updatedTime = now;
+ }
+
+ @PreUpdate
+ protected void onUpdate() {
+ updatedTime = LocalDateTime.now();
+ }
+
+ /**
+ * 更新设备心跳时间
+ */
+ public void updateHeartbeat() {
+ this.lastHeartbeat = LocalDateTime.now();
+ }
+
+ /**
+ * 设置设备在线状态
+ *
+ * @param online 是否在线
+ */
+ public void setOnlineStatus(boolean online) {
+ this.isOnline = online;
+ if (online) {
+ updateHeartbeat();
+ }
+ }
+
+ /**
+ * 检查设备是否可用(激活且在线)
+ *
+ * @return true如果设备可用,false否则
+ */
+ public boolean isAvailable() {
+ return Boolean.TRUE.equals(isActive) && Boolean.TRUE.equals(isOnline);
+ }
+
+ /**
+ * 检查设备心跳是否超时
+ *
+ * @param timeoutMinutes 超时时间(分钟)
+ * @return true如果心跳超时,false否则
+ */
+ public boolean isHeartbeatTimeout(int timeoutMinutes) {
+ if (lastHeartbeat == null) {
+ return true;
+ }
+ return lastHeartbeat.isBefore(LocalDateTime.now().minusMinutes(timeoutMinutes));
+ }
+
+ /**
+ * 获取设备状态描述
+ *
+ * @return 设备状态字符串
+ */
+ public String getStatusDescription() {
+ if (!Boolean.TRUE.equals(isActive)) {
+ return "未激活";
+ }
+ if (!Boolean.TRUE.equals(isOnline)) {
+ return "离线";
+ }
+ if (isHeartbeatTimeout(5)) {
+ return "心跳超时";
+ }
+ return "正常";
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/config/GracefulShutdownConfig.java b/qaup-collision/src/main/java/com/qaup/collision/config/GracefulShutdownConfig.java
new file mode 100644
index 00000000..20deabfa
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/config/GracefulShutdownConfig.java
@@ -0,0 +1,45 @@
+package com.qaup.collision.config;
+
+import com.qaup.collision.datacollector.server.TrafficLightTcpServer;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+
+import jakarta.annotation.PreDestroy;
+
+/**
+ * 优雅关闭配置
+ *
+ * 确保系统关闭时所有资源都能正确释放
+ */
+@Slf4j
+@Configuration
+public class GracefulShutdownConfig {
+
+ @Autowired
+ private TrafficLightTcpServer trafficLightTcpServer;
+
+ /**
+ * 系统关闭时的清理工作
+ */
+ @PreDestroy
+ public void onShutdown() {
+ log.info("系统正在关闭,开始清理资源...");
+
+ try {
+ // 关闭红绿灯TCP服务器
+ if (trafficLightTcpServer != null) {
+ trafficLightTcpServer.stopServer();
+ log.info("红绿灯TCP服务器已关闭");
+ }
+
+ // 等待一段时间确保所有连接都已关闭
+ Thread.sleep(1000);
+
+ log.info("系统资源清理完成");
+
+ } catch (Exception e) {
+ log.error("系统关闭时清理资源异常", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/qaup-collision/src/main/java/com/qaup/collision/controller/HealthController.java b/qaup-collision/src/main/java/com/qaup/collision/controller/HealthController.java
new file mode 100644
index 00000000..44909183
--- /dev/null
+++ b/qaup-collision/src/main/java/com/qaup/collision/controller/HealthController.java
@@ -0,0 +1,170 @@
+package com.qaup.collision.controller;
+
+import com.qaup.collision.datacollector.server.TrafficLightTcpServer;
+import com.qaup.collision.datacollector.service.TrafficLightDataCollector;
+import com.qaup.collision.dataprocessing.service.TrafficLightService;
+import com.qaup.collision.dataprocessing.service.IntersectionService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 健康检查控制器
+ *
+ * 提供系统健康状态检查接口,包括红绿灯系统的状态
+ */
+@Slf4j
+@RestController
+@RequestMapping("/health")
+public class HealthController {
+
+ @Autowired
+ private TrafficLightTcpServer trafficLightTcpServer;
+
+ @Autowired
+ private TrafficLightDataCollector trafficLightDataCollector;
+
+ @Autowired
+ private TrafficLightService trafficLightService;
+
+ @Autowired
+ private IntersectionService intersectionService;
+
+ /**
+ * 系统整体健康检查
+ */
+ @GetMapping
+ public ResponseEntity