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

597 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# QAUP机场车辆管理系统使用指南
## 系统概述
QAUP是一个集成的机场车辆管理系统包含
- **基础信息管理**:车辆档案、驾驶员信息、车辆类型等
- **实时位置监控**基于PostGIS的空间数据管理
- **碰撞避免系统**:实时安全规则检测和预警
- **轨迹管理**:车辆历史路径记录和分析
- **航空器生命周期模拟**CA3456航空器状态和路由模拟系统
## API接口测试
### 航空器生命周期模拟API
系统提供了完整的航空器生命周期模拟API支持CA3456航空器的状态循环和路由管理。
#### 1. 登录认证
```bash
# 基本登录(推荐)
curl -X POST "http://localhost:8090/login?username=dianxin&password=dianxin@123"
# 使用表单数据登录
curl -X POST "http://localhost:8090/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=dianxin&password=dianxin@123"
# 使用JSON数据登录
curl -X POST "http://localhost:8090/login" \
-H "Content-Type: application/json" \
-d '{"username":"dianxin","password":"dianxin@123"}'
```
**预期响应:**
```json
{
"data": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzI3ODMwOTAsInVzZXJuYW1lIjoiYWRtaW4ifQ.y9feEL_9NT8UzED9NNkb0Ln6C-PBoufiSHWobWe5vWY",
"msg": "登入成功",
"status": 200
}
```
#### 2. 航空器状态查询
```bash
# 查询CA3456当前状态
curl -X GET "http://localhost:8090/aircraftStatusController/getAircraftStatus" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzI3ODMwOTAsInVzZXJuYW1lIjoiYWRtaW4ifQ.y9feEL_9NT8UzED9NNkb0Ln6C-PBoufiSHWobWe5vWY"
```
**预期响应:**
```json
{
"data": {
"contactCross": "F1",
"flightNo": "CA3456",
"inRunway": "35",
"outRunway": "34",
"seat": "138",
"timestamp": 1752567616199,
"type": "IN" // 状态: IN(进港), ARRIVED(到达), OUT(出港)
},
"msg": "航空器状态查询成功",
"status": 200
}
```
#### 3. 进港路由查询
```bash
# 查询进港滑行路线
curl -X GET "http://localhost:8090/runwayPathPlanningController/findArrTaxiwayByRunwayAndContactCrossAndSeat?inRunway=35&outRunway=34&contactCross=F1&seat=138" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzI3ODMwOTAsInVzZXJuYW1lIjoiYWRtaW4ifQ.y9feEL_9NT8UzED9NNkb0Ln6C-PBoufiSHWobWe5vWY"
```
**预期响应:**
```json
{
"data": {
"type": "IN",
"status": "COMPLETE",
"codes": "F1,L4,138",
"geometry": null,
"geoPath": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[120.086263, 36.370484],
[120.085000, 36.370000],
[120.084000, 36.369500],
[120.083000, 36.369000],
[120.082000, 36.368500],
[120.081000, 36.368000],
[120.080996, 36.369105]
]
},
"properties": {
"code": "L4"
}
}
]
}
},
"msg": "进港滑行路线查询成功",
"status": 200
}
```
#### 4. 出港路由查询
```bash
# 查询出港滑行路线
curl -X GET "http://localhost:8090/runwayPathPlanningController/findDepTaxiwayByRunwayAndContactCrossAndSeat?inRunway=35&outRunway=34&startSeat=138" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzI3ODMwOTAsInVzZXJuYW1lIjoiYWRtaW4ifQ.y9feEL_9NT8UzED9NNkb0Ln6C-PBoufiSHWobWe5vWY"
```
**预期响应:**
```json
{
"data": {
"type": "OUT",
"status": "COMPLETE",
"codes": "138,L4,F1",
"geometry": null,
"geoPath": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[120.080996, 36.369105],
[120.081000, 36.368000],
[120.082000, 36.368500],
[120.083000, 36.369000],
[120.084000, 36.369500],
[120.085000, 36.370000],
[120.086263, 36.370484]
]
},
"properties": {
"code": "L4"
}
}
]
}
},
"msg": "出港滑行路线查询成功",
"status": 200
}
```
#### 5. 状态循环测试
```bash
# 连续监控CA3456状态变化
for i in {1..6}; do
echo "=== 第 $i 次调用 ($(date +%H:%M:%S)) ==="
curl -s -X GET "http://localhost:8090/aircraftStatusController/getAircraftStatus" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzI3ODMwOTAsInVzZXJuYW1lIjoiYWRtaW4ifQ.y9feEL_9NT8UzED9NNkb0Ln6C-PBoufiSHWobWe5vWY" \
| python3 -c "import sys,json; data=json.load(sys.stdin); print(f'状态: {data[\"data\"][\"type\"]}, 航班号: {data[\"data\"][\"flightNo\"]}, 时间戳: {data[\"data\"][\"timestamp\"]}')"
sleep 15
done
```
**预期输出:**
```
=== 第 1 次调用 (16:22:45) ===
状态: IN, 航班号: CA3456, 时间戳: 1752567765233
=== 第 2 次调用 (16:23:00) ===
状态: IN, 航班号: CA3456, 时间戳: 1752567780372
=== 第 3 次调用 (16:23:15) ===
状态: ARRIVED, 航班号: CA3456, 时间戳: 1752567795496
=== 第 4 次调用 (16:23:30) ===
状态: ARRIVED, 航班号: CA3456, 时间戳: 1752567810629
=== 第 5 次调用 (16:23:45) ===
状态: IN, 航班号: CA3456, 时间戳: 1752567825769
=== 第 6 次调用 (16:24:00) ===
状态: IN, 航班号: CA3456, 时间戳: 1752567840897
```
#### 6. 路由API简化测试
```bash
# 简化的路由测试
echo "=== 测试进港路由 ==="
curl -s -X GET "http://localhost:8090/runwayPathPlanningController/findArrTaxiwayByRunwayAndContactCrossAndSeat?inRunway=35&outRunway=34&contactCross=F1&seat=138" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzI3ODMwOTAsInVzZXJuYW1lIjoiYWRtaW4ifQ.y9feEL_9NT8UzED9NNkb0Ln6C-PBoufiSHWobWe5vWY" \
| python3 -c "import sys,json; data=json.load(sys.stdin); print(f'路由类型: {data[\"data\"][\"type\"]}, 编码: {data[\"data\"][\"codes\"]}, 状态: {data[\"data\"][\"status\"]}')"
echo "=== 测试出港路由 ==="
curl -s -X GET "http://localhost:8090/runwayPathPlanningController/findDepTaxiwayByRunwayAndContactCrossAndSeat?inRunway=35&outRunway=34&startSeat=138" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzI3ODMwOTAsInVzZXJuYW1lIjoiYWRtaW4ifQ.y9feEL_9NT8UzED9NNkb0Ln6C-PBoufiSHWobWe5vWY" \
| python3 -c "import sys,json; data=json.load(sys.stdin); print(f'路由类型: {data[\"data\"][\"type\"]}, 编码: {data[\"data\"][\"codes\"]}, 状态: {data[\"data\"][\"status\"]}')"
```
### CA3456生命周期说明
CA3456航空器按照以下周期进行状态模拟
1. **进港阶段30秒**`type = "IN"`
- 航空器正在进场,执行进港滑行
- 使用进港路由F1,L4,138
2. **停留阶段60秒**`type = "ARRIVED"`
- 航空器已到达机位,进行客货作业
- 停留在138机位
3. **出港阶段30秒**`type = "OUT"`
- 航空器开始出港,执行出港滑行
- 使用出港路由138,L4,F1
4. **循环周期**总计122秒包含2秒状态切换时间
### WebSocket连接测试
系统支持WebSocket实时推送可以通过以下方式连接
```javascript
// WebSocket连接示例
const ws = new WebSocket('ws://localhost:8080/ws');
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === 'aircraftRouteUpdate') {
console.log('收到航空器路由更新:', data.data);
}
};
```
### 故障排除
#### 常见错误
1. **认证失败401**
- 检查token是否正确
- 确认Authorization header格式`Bearer <token>`
2. **连接超时**
- 检查Mock服务是否运行在端口8090
- 确认Java服务是否运行在端口8080
3. **状态不变化**
- 等待完整的状态周期122秒
- 检查Mock服务日志
#### 服务状态检查
```bash
# 检查Mock服务状态
curl -I http://localhost:8090/login
# 检查Java服务状态
curl -I http://localhost:8080/actuator/health
```
## 核心数据结构
### 主要表关系
```
sys_vehicle_info (基础信息)
├── vehicle_id: 数字ID (主键)
└── license_plate_number: 车牌号
vehicle_locations (实时位置)
├── vehicle_id: 车牌号 (业务标识)
├── license_plate: 车牌号 (明确语义)
└── sys_vehicle_id: 关联数字ID
通过车牌号关联: license_plate_number ↔ license_plate
```
### 业务视图
- `vehicle_complete_info`: 车辆基础信息 + 最新位置
- `vehicle_info_with_location`: 车辆信息与位置详细关联
- `vehicle_status_summary`: 车辆实时状态统计
- `vehicle_trajectory_view`: 车辆轨迹查询
## 实际使用指南
### 1. 车辆数据查询
#### 基础查询
```sql
-- 查询所有车辆基础信息
SELECT vehicle_id, license_plate_number, brand, owning_unit, contact_person
FROM sys_vehicle_info;
-- 查询指定车辆详细信息
SELECT * FROM sys_vehicle_info
WHERE license_plate_number = '京A12345';
```
#### 车辆完整信息查询(推荐)
```sql
-- 根据车牌号查询车辆完整信息(基础信息+最新位置)
SELECT vehicle_plate, brand, owning_unit, status,
longitude, latitude, speed, last_update_time
FROM vehicle_info_with_location
WHERE vehicle_plate = '京A12345';
-- 查询所有活跃车辆
SELECT vehicle_plate, brand, status, speed, last_update_time
FROM vehicle_info_with_location
WHERE status = 'ACTIVE'
ORDER BY last_update_time DESC;
-- 查询离线车辆
SELECT vehicle_plate, brand, status, last_update_time
FROM vehicle_info_with_location
WHERE status = 'OFFLINE'
ORDER BY last_update_time DESC;
```
#### 车辆状态统计
```sql
-- 各类型车辆状态统计
SELECT vehicle_type, total_vehicles, active_vehicles,
inactive_vehicles, avg_speed, max_speed
FROM vehicle_status_summary;
-- 当前活跃车辆数量
SELECT COUNT(*) as active_count
FROM vehicle_info_with_location
WHERE status = 'ACTIVE';
```
### 2. 空间查询
#### 位置范围查询
```sql
-- 查询指定经纬度范围内的车辆
SELECT vi.vehicle_plate, vi.brand, vi.speed, vi.longitude, vi.latitude
FROM vehicle_info_with_location vi
WHERE vi.longitude BETWEEN 116.3 AND 116.4
AND vi.latitude BETWEEN 39.9 AND 40.0
AND vi.status = 'ACTIVE';
-- 查询距离指定点特定距离内的车辆使用PostGIS函数
SELECT vl.vehicle_id, vl.speed, ST_AsText(vl.location) as position,
ST_Distance(vl.location, ST_Point(116.33, 39.95)) as distance_meters
FROM vehicle_locations vl
WHERE ST_DWithin(vl.location, ST_Point(116.33, 39.95), 1000) -- 1000米范围内
AND vl.timestamp > NOW() - INTERVAL '10 minutes'
ORDER BY distance_meters;
```
#### 机场区域查询
```sql
-- 查询特定区域内的车辆
SELECT vl.vehicle_id, vl.speed, aa.name as area_name
FROM vehicle_locations vl
JOIN airport_areas aa ON ST_Within(vl.location, aa.boundary)
WHERE aa.area_id = 'RUNWAY_01'
AND vl.timestamp > NOW() - INTERVAL '5 minutes';
-- 查询所有机场区域
SELECT area_id, name, type, speed_limit_kph, restricted
FROM airport_areas
WHERE enabled = true
ORDER BY name;
```
### 3. 轨迹数据查询
#### 车辆历史轨迹
```sql
-- 查询车辆最近7天的轨迹统计
SELECT vehicle_plate, trajectory_date, total_distance,
max_speed, avg_speed, duration_seconds
FROM vehicle_trajectory_view
WHERE vehicle_plate = '京A12345'
AND trajectory_date >= CURRENT_DATE - INTERVAL '7 days'
ORDER BY trajectory_date DESC;
-- 查询车辆详细位置历史
SELECT vehicle_id, ST_AsText(location) as position,
speed, heading, timestamp
FROM vehicle_locations
WHERE vehicle_id = '京A12345'
AND timestamp BETWEEN '2025-01-15 08:00:00' AND '2025-01-15 18:00:00'
ORDER BY timestamp;
```
#### 轨迹分析
```sql
-- 统计车辆每日行驶距离
SELECT vehicle_plate,
DATE(start_time) as date,
SUM(total_distance) as daily_distance,
MAX(max_speed) as daily_max_speed
FROM vehicle_trajectory_view
WHERE vehicle_plate = '京A12345'
AND start_time >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY vehicle_plate, DATE(start_time)
ORDER BY date DESC;
```
### 4. 安全规则和事件查询
#### 规则违反事件
```sql
-- 查询最近的违规事件
SELECT event_id, rule_id, subject_id as vehicle_plate,
violation_type, severity, ST_AsText(location) as violation_location,
detected_at, response_status
FROM rule_violation_events
WHERE detected_at > NOW() - INTERVAL '24 hours'
ORDER BY detected_at DESC;
-- 查询特定车辆的违规历史
SELECT event_id, violation_type, severity, detected_at
FROM rule_violation_events
WHERE subject_id = '京A12345'
AND subject_type = 'VEHICLE'
ORDER BY detected_at DESC;
```
#### 安全规则管理
```sql
-- 查询所有活跃的安全规则
SELECT rule_id, rule_name, rule_category, alert_level, status
FROM spatial_rules
WHERE status = 'ACTIVE'
ORDER BY priority, rule_name;
```
### 5. 数据同步管理
#### 数据同步操作
```sql
-- 执行车辆ID同步当新增车辆信息时
SELECT update_sys_vehicle_id();
-- 检查数据同步状态
SELECT
'vehicle_locations' as table_name,
COUNT(*) as total_records,
COUNT(license_plate) as has_license_plate,
COUNT(sys_vehicle_id) as has_sys_vehicle_id
FROM vehicle_locations
UNION ALL
SELECT
'vehicle_trajectories' as table_name,
COUNT(*) as total_records,
COUNT(license_plate) as has_license_plate,
COUNT(sys_vehicle_id) as has_sys_vehicle_id
FROM vehicle_trajectories;
```
#### 数据清理
```sql
-- 清理历史位置数据保留最近30天
DELETE FROM vehicle_locations
WHERE timestamp < NOW() - INTERVAL '30 days';
-- 清理已解决的违规事件保留最近7天
DELETE FROM rule_violation_events
WHERE response_status = 'RESOLVED'
AND resolved_at < NOW() - INTERVAL '7 days';
```
## 开发建议
### ✅ 推荐做法
1. **统一使用车牌号作为业务标识符**
```sql
-- 推荐:使用车牌号查询
SELECT * FROM vehicle_info_with_location WHERE vehicle_plate = '京A12345';
```
2. **优先使用业务视图进行复杂查询**
```sql
-- 推荐:使用视图获取完整信息
SELECT * FROM vehicle_info_with_location;
-- 避免:手动关联多个表
-- SELECT * FROM sys_vehicle_info vi JOIN vehicle_locations vl ON ...;
```
3. **定期执行数据同步**
```sql
-- 建议在车辆信息变更后执行
SELECT update_sys_vehicle_id();
```
4. **使用PostGIS函数进行空间查询**
```sql
-- 推荐使用PostGIS函数
SELECT * FROM vehicle_locations
WHERE ST_DWithin(location, ST_Point(116.33, 39.95), 1000);
```
### ⚠️ 注意事项
1. **数据类型一致性**
- `sys_vehicle_info.vehicle_id`: BIGINT数字ID
- `vehicle_locations.vehicle_id`: VARCHAR车牌号
- 关联通过:`license_plate_number` ↔ `license_plate`
2. **时区处理**
- 新表使用 `TIMESTAMP WITH TIME ZONE`
- 查询时注意时区一致性
3. **空间坐标系**
- 所有空间数据使用 WGS84 坐标系SRID: 4326
- 经度范围:-180 到 180
- 纬度范围:-90 到 90
4. **性能优化**
- 大量空间查询时使用已建立的GIST索引
- 时间范围查询利用时间戳索引
- 避免全表扫描善用WHERE条件
## 常用查询模板
### 实时监控查询
```sql
-- 车辆实时状态大屏
SELECT
COUNT(*) as total_vehicles,
COUNT(CASE WHEN status = 'ACTIVE' THEN 1 END) as active_vehicles,
COUNT(CASE WHEN status = 'INACTIVE' THEN 1 END) as inactive_vehicles,
COUNT(CASE WHEN status = 'OFFLINE' THEN 1 END) as offline_vehicles,
AVG(CASE WHEN status = 'ACTIVE' THEN speed END) as avg_speed
FROM vehicle_info_with_location;
```
### 区域车辆分布
```sql
-- 各区域车辆分布统计
SELECT
aa.name as area_name,
aa.type as area_type,
COUNT(vl.vehicle_id) as vehicle_count
FROM airport_areas aa
LEFT JOIN vehicle_locations vl ON ST_Within(vl.location, aa.boundary)
AND vl.timestamp > NOW() - INTERVAL '5 minutes'
WHERE aa.enabled = true
GROUP BY aa.area_id, aa.name, aa.type
ORDER BY vehicle_count DESC;
```
### 安全监控查询
```sql
-- 安全事件实时监控
SELECT
COUNT(*) as total_events,
COUNT(CASE WHEN severity = 'CRITICAL' THEN 1 END) as critical_events,
COUNT(CASE WHEN severity = 'HIGH' THEN 1 END) as high_events,
COUNT(CASE WHEN response_status = 'PENDING' THEN 1 END) as pending_events
FROM rule_violation_events
WHERE detected_at > NOW() - INTERVAL '1 hour';
```
## 故障排除
### 常见问题
1. **车辆位置数据无法关联**
- 检查车牌号格式是否一致
- 执行数据同步:`SELECT update_sys_vehicle_id();`
2. **空间查询结果为空**
- 确认坐标系是否为WGS84SRID: 4326
- 检查经纬度值是否合理
3. **性能问题**
- 检查是否使用了适当的索引
- 时间范围查询添加时间限制条件
### 数据检查命令
```sql
-- 检查PostGIS扩展
SELECT PostGIS_Version();
-- 检查表结构
\d+ vehicle_locations
\d+ sys_vehicle_info
-- 检查数据完整性
SELECT table_name, column_name
FROM information_schema.columns
WHERE table_name LIKE 'vehicle%'
AND column_name IN ('license_plate', 'sys_vehicle_id');
```
---
## 联系支持
如有问题,请查看:
- 系统日志:`logs/` 目录
- 数据库日志PostgreSQL日志
- 开发文档:`doc/` 目录下的相关文档