修改mock进出港和按路由运动不一致的情况
This commit is contained in:
parent
a9c2e7e32d
commit
317721d1a8
2090670
deploy/qaup_database_export.sql
Normal file
2090670
deploy/qaup_database_export.sql
Normal file
File diff suppressed because it is too large
Load Diff
115
doc/deploy/database_migration.md
Normal file
115
doc/deploy/database_migration.md
Normal file
@ -0,0 +1,115 @@
|
||||
# PostgreSQL 数据库迁移指南
|
||||
|
||||
## 概述
|
||||
本文档描述如何将本地 PostgreSQL 数据库完全覆盖导入到远程服务器。
|
||||
|
||||
**场景:**
|
||||
- 本地数据库用户:postgres
|
||||
- 远程数据库用户:qaup
|
||||
- 数据库名称:qaup
|
||||
- 操作方式:完全覆盖
|
||||
|
||||
## 第一步:本地数据库导出
|
||||
|
||||
### 导出完整数据库
|
||||
```bash
|
||||
# 导出数据库(包含结构和数据,处理用户名差异)
|
||||
pg_dump -h localhost -U postgres -d qaup --no-owner --no-privileges --clean --if-exists -f qaup_database_export.sql
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
- `--no-owner`: 不包含对象所有者信息,避免用户名冲突
|
||||
- `--no-privileges`: 不包含权限设置,导入后重新设置权限
|
||||
- `--clean --if-exists`: 清理现有对象(如果存在)
|
||||
- `-f`: 指定输出文件名
|
||||
|
||||
## 第二步:远程服务器完全覆盖
|
||||
|
||||
```bash
|
||||
# 1. 删除现有数据库
|
||||
psql -U qaup -d postgres -c "DROP DATABASE IF EXISTS qaup;"
|
||||
|
||||
# 2. 重新创建数据库
|
||||
psql -U qaup -d postgres -c "CREATE DATABASE qaup OWNER qaup;"
|
||||
|
||||
# 3. 设置PostGIS扩展
|
||||
psql -U qaup -d qaup -c "CREATE EXTENSION IF NOT EXISTS postgis;"
|
||||
|
||||
# 4. 导入数据
|
||||
psql -U qaup -d qaup -f qaup_database_export.sql
|
||||
```
|
||||
|
||||
## 第三步:验证导入结果
|
||||
|
||||
### 检查数据库结构
|
||||
```bash
|
||||
# 查看所有表
|
||||
psql -U qaup -d qaup -c "\dt"
|
||||
|
||||
# 查看特定表结构
|
||||
psql -U qaup -d qaup -c "\d traffic_lights"
|
||||
```
|
||||
|
||||
### 验证数据完整性
|
||||
```bash
|
||||
# 检查关键表的数据量
|
||||
psql -U qaup -d qaup -c "SELECT count(*) FROM traffic_lights;"
|
||||
psql -U qaup -d qaup -c "SELECT count(*) FROM intersections;"
|
||||
psql -U qaup -d qaup -c "SELECT count(*) FROM sys_vehicle_info;"
|
||||
```
|
||||
|
||||
### 检查用户权限
|
||||
```bash
|
||||
# 确保qaup用户拥有所有表的权限
|
||||
psql -U qaup -d qaup -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO qaup;"
|
||||
psql -U qaup -d qaup -c "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO qaup;"
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **备份重要性**:操作前确保远程数据库已备份(如有重要数据)
|
||||
2. **网络连接**:确保网络稳定,大数据库传输可能需要较长时间
|
||||
3. **磁盘空间**:确认远程服务器有足够存储空间
|
||||
4. **权限检查**:确保qaup用户有CREATE DATABASE权限(方案A)
|
||||
5. **应用停机**:建议在应用停机时间窗口执行,避免数据不一致
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 连接失败
|
||||
```bash
|
||||
# 检查用户权限
|
||||
psql -U qaup -d postgres -c "SELECT current_user;"
|
||||
```
|
||||
|
||||
### 导入错误
|
||||
```bash
|
||||
# 查看详细错误信息
|
||||
psql -U qaup -d qaup -f qaup_database_export.sql 2>&1 | tee import.log
|
||||
```
|
||||
|
||||
### 权限问题
|
||||
```bash
|
||||
# 重置所有权限
|
||||
psql -U qaup -d qaup -c "
|
||||
GRANT ALL PRIVILEGES ON DATABASE qaup TO qaup;
|
||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO qaup;
|
||||
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO qaup;
|
||||
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO qaup;
|
||||
"
|
||||
```
|
||||
|
||||
## 完成后清理
|
||||
|
||||
```bash
|
||||
# 删除本地导出文件(可选)
|
||||
rm qaup_database_export.sql
|
||||
|
||||
# 删除临时脚本(如果使用了方案B)
|
||||
rm drop_tables.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**创建时间:** 2025-09-25
|
||||
**适用版本:** PostgreSQL 12+
|
||||
**测试环境:** QAUP-Management 1.0.1
|
||||
298
qaup-admin/src/main/resources/application-deploy.yml
Normal file
298
qaup-admin/src/main/resources/application-deploy.yml
Normal file
@ -0,0 +1,298 @@
|
||||
# 项目相关配置
|
||||
qaup:
|
||||
# 名称
|
||||
name: Qaup
|
||||
# 版本
|
||||
version: 1.0.1
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/qaup/uploadPath,Linux配置 /home/qaup/uploadPath)
|
||||
profile: ${UPLOAD_PATH:/app/uploadPath}
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
captchaType: math
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8080
|
||||
port: 8080
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 2000
|
||||
# 使用JDK21虚拟线程,不需要限制线程数
|
||||
threads:
|
||||
# 虚拟线程模式下可以处理更多请求
|
||||
max: 2000
|
||||
# Tomcat启动初始化的线程数
|
||||
min-spare: 50
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.qaup: debug
|
||||
org.springframework: warn
|
||||
|
||||
# 用户配置
|
||||
user:
|
||||
password:
|
||||
# 密码最大错误次数
|
||||
maxRetryCount: 5
|
||||
# 密码锁定时间(默认10分钟)
|
||||
lockTime: 10
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
profiles:
|
||||
active: dev,druid
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 10MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 20MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: true
|
||||
# 重启目录
|
||||
additional-paths: src/main/java
|
||||
# 排除目录
|
||||
exclude: WEB-INF/**
|
||||
jackson:
|
||||
# 日期格式化
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
serialization:
|
||||
# 格式化输出
|
||||
indent_output: false
|
||||
# 忽略无法转换的对象
|
||||
fail_on_empty_beans: false
|
||||
deserialization:
|
||||
# 允许对象忽略json中不存在的属性
|
||||
fail_on_unknown_properties: false
|
||||
# redis 配置
|
||||
data:
|
||||
redis:
|
||||
# 地址
|
||||
host: 172.17.0.4
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码
|
||||
password:
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
|
||||
# ==================== CollisionAvoidanceSystem 配置整合 ====================
|
||||
|
||||
# Flyway数据库迁移配置
|
||||
flyway:
|
||||
# 启用Flyway
|
||||
enabled: true
|
||||
# 迁移脚本位置
|
||||
locations: classpath:db/migration
|
||||
# 基线迁移设置
|
||||
baseline-on-migrate: true
|
||||
baseline-version: 1.0.0
|
||||
baseline-description: "Initial baseline from existing database"
|
||||
# 迁移验证
|
||||
validate-on-migrate: true
|
||||
# 生产环境禁用clean操作
|
||||
clean-disabled: true
|
||||
# 不允许乱序迁移
|
||||
out-of-order: false
|
||||
# 编码设置
|
||||
encoding: UTF-8
|
||||
# 占位符配置
|
||||
placeholder-replacement: false
|
||||
|
||||
# JPA配置(collision模块空间数据处理)
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: none # 使用数据库管理方式
|
||||
show-sql: false
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: false
|
||||
jdbc:
|
||||
lob:
|
||||
non_contextual_creation: true
|
||||
batch_size: 50
|
||||
fetch_size: 50
|
||||
cache:
|
||||
use_second_level_cache: false
|
||||
use_query_cache: false
|
||||
order_inserts: true
|
||||
order_updates: true
|
||||
batch_versioned_data: true
|
||||
generate_statistics: false
|
||||
|
||||
# token配置
|
||||
token:
|
||||
# 令牌自定义标识
|
||||
header: Authorization
|
||||
# 令牌密钥
|
||||
secret: abcdefghijklmnopqrstuvwxyz
|
||||
# 令牌有效期(默认30分钟)
|
||||
expireTime: 30
|
||||
|
||||
# MyBatis配置
|
||||
mybatis:
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.qaup.system.domain,com.qaup.common.core.domain.entity,com.qaup.generator.domain,com.qaup.quartz.domain,com.qaup.collision.common.model.spatial,com.qaup.collision.datacollector.model.dto,com.qaup.collision.geofence.model.entity
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 加载全局的配置文件
|
||||
configLocation: classpath:mybatis/mybatis-config.xml
|
||||
|
||||
# PageHelper分页插件
|
||||
pagehelper:
|
||||
helperDialect: postgresql
|
||||
reasonable: true
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
# SpringDoc 配置
|
||||
springdoc:
|
||||
swagger-ui:
|
||||
path: /swagger-ui.html # Swagger UI 访问路径
|
||||
url: /v3/api-docs # OpenAPI JSON 文档路径
|
||||
disable-swagger-default-url: true
|
||||
api-docs:
|
||||
path: /v3/api-docs # OpenAPI JSON 文档路径
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
excludes: /system/notice
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
|
||||
# 数据采集配置(collision模块)
|
||||
data:
|
||||
collector:
|
||||
# 数据采集间隔,单位:毫秒(高频采集保证数据新鲜度)
|
||||
interval: 250
|
||||
# 检测和推送间隔配置
|
||||
detection:
|
||||
# 检测间隔,单位:毫秒(控制围栏检测、冲突检测、违规检测和WebSocket推送频率)
|
||||
interval: 1000
|
||||
# 机场数据源配置
|
||||
airport-api:
|
||||
base-url: http://10.64.58.228:8090
|
||||
endpoints:
|
||||
login: /login
|
||||
refresh: /userInfoController/refreshToken
|
||||
aircraft: /openApi/getCurrentFlightPositions
|
||||
vehicle: /openApi/getCurrentVehiclePositions
|
||||
arrival-route: /runwayPathPlanningController/findArrTaxiwayByRunwayAndContactCrossAndSeat
|
||||
departure-route: /runwayPathPlanningController/findDepTaxiwayByRunwayAndContactCrossAndSeat
|
||||
aircraft-status: /aircraftStatusController/getAircraftStatus
|
||||
flight-notification: /openApi/getInboundAndOutboundFlightsNotification
|
||||
|
||||
auth:
|
||||
username: dianxin
|
||||
password: dianxin@123
|
||||
# 无人车厂商数据源配置
|
||||
vehicle-api:
|
||||
base-url: http://10.64.58.228:8091
|
||||
endpoints:
|
||||
vehicle-command: /api/VehicleCommandInfo
|
||||
# 通用车辆状态API端点(符合universal_autonomous_vehicle_api规范)
|
||||
universal-status: /api/v1/vehicles/{vehicleId}/status
|
||||
timeout: 1000
|
||||
retry-attempts: 3
|
||||
# 无人车数据持久化配置
|
||||
unmanned-vehicle:
|
||||
persistence:
|
||||
enabled: true
|
||||
batch-size: 50
|
||||
location-retention-days: 90
|
||||
command-retention-days: 365
|
||||
command:
|
||||
timeout: 1000
|
||||
retry-attempts: 3
|
||||
validation:
|
||||
enabled: true
|
||||
strict-mode: false
|
||||
retention:
|
||||
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"
|
||||
|
||||
processing:
|
||||
# 是否启用统计功能
|
||||
enable-statistics: true
|
||||
# 统计信息输出间隔(毫秒)
|
||||
statistics-interval: 60000
|
||||
# 是否启用调试日志
|
||||
enable-debug-log: false
|
||||
# 信号处理超时时间(毫秒)
|
||||
signal-process-timeout: 5000
|
||||
|
||||
# 坐标系统配置(collision模块)
|
||||
coordinate-system:
|
||||
airport:
|
||||
center-longitude: 120.0834104
|
||||
center-latitude: 36.35406879
|
||||
|
||||
# 性能监控配置(collision模块扩展)
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: "*"
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
metrics:
|
||||
export:
|
||||
simple:
|
||||
enabled: true
|
||||
enable:
|
||||
hikari: true
|
||||
jvm: true
|
||||
jmx:
|
||||
enabled: true
|
||||
@ -103,32 +103,21 @@ AIRCRAFT_SIZE_M = 30.0
|
||||
VEHICLE_SIZE_M = 10.0
|
||||
|
||||
# 航班数据配置 - 用于进出港查询接口(简化版)
|
||||
# 修改为与路由参数配置一致的航班
|
||||
current_time = time.time()
|
||||
# 移除时间周期控制,仅保留基础信息供航班通知使用
|
||||
flight_data = {
|
||||
"CA1234": { # 出港航班
|
||||
"flightNo": "CA1234",
|
||||
"type": "OUT",
|
||||
"runway": "17",
|
||||
"contactCross": "A2",
|
||||
"seat": "201",
|
||||
"cycle_start": current_time,
|
||||
"active_duration": 60, # 1分钟活跃期
|
||||
"gap_duration": 5, # 5秒间隔期
|
||||
"fixed_time": int(current_time * 1000), # 固定的滑出时间
|
||||
"status": "active"
|
||||
"seat": "201"
|
||||
},
|
||||
"MU5123": { # 进港航班 - 使用真实路由
|
||||
"flightNo": "MU5123",
|
||||
"type": "IN",
|
||||
"runway": "35",
|
||||
"contactCross": "F1", # F1滑行道
|
||||
"seat": "138", # 138机位
|
||||
"cycle_start": current_time,
|
||||
"active_duration": 60, # 1分钟活跃期
|
||||
"gap_duration": 5, # 5秒间隔期
|
||||
"fixed_time": int(current_time * 1000), # 固定的落地时间
|
||||
"status": "active"
|
||||
"seat": "138" # 138机位
|
||||
}
|
||||
}
|
||||
|
||||
@ -1395,6 +1384,11 @@ class AircraftRouteFollower:
|
||||
self.gate_position = None # 机位坐标
|
||||
self._status_start_time = time.time() # 状态开始时间,用于简化状态管理
|
||||
|
||||
# 新增状态管理属性
|
||||
self.flight_status = 'idle' # 飞机状态:'idle', 'in_route', 'at_gate', 'waiting'
|
||||
self.wait_until = 0.0 # 等待结束时间戳
|
||||
self.waiting_duration = 5.0 # 路径完成后的等待时间(秒)
|
||||
|
||||
# 解析航空器路由路径
|
||||
self._parse_routes()
|
||||
|
||||
@ -1450,6 +1444,8 @@ class AircraftRouteFollower:
|
||||
self.current_point_index = 0
|
||||
self.route_progress = 0.0
|
||||
self.is_at_gate = False
|
||||
self.flight_status = 'in_route' # 设置为路径运行状态
|
||||
self.wait_until = 0.0 # 清除等待时间
|
||||
logging.info(f"航空器 {self.flight_no} 开始进港路径跟随")
|
||||
|
||||
elif route_type == "departure" and self.departure_points:
|
||||
@ -1458,6 +1454,8 @@ class AircraftRouteFollower:
|
||||
self.current_point_index = 0
|
||||
self.route_progress = 0.0
|
||||
self.is_at_gate = False
|
||||
self.flight_status = 'in_route' # 设置为路径运行状态
|
||||
self.wait_until = 0.0 # 清除等待时间
|
||||
logging.info(f"航空器 {self.flight_no} 开始出港路径跟随")
|
||||
|
||||
else:
|
||||
@ -1475,9 +1473,19 @@ class AircraftRouteFollower:
|
||||
Returns:
|
||||
bool: 是否到达路径终点
|
||||
"""
|
||||
current_time = time.time()
|
||||
|
||||
# 检查是否在等待期
|
||||
if current_time < self.wait_until:
|
||||
self.flight_status = 'waiting'
|
||||
return False # 还在等待中,不更新位置
|
||||
|
||||
if not self.route_points or self.current_point_index >= len(self.route_points):
|
||||
return True # 路径已完成
|
||||
|
||||
# 设置状态为路径运行中
|
||||
self.flight_status = 'in_route'
|
||||
|
||||
# 获取当前位置
|
||||
current_lat = to_float_safe(aircraft.get("latitude", 0))
|
||||
current_lon = to_float_safe(aircraft.get("longitude", 0))
|
||||
@ -1494,27 +1502,45 @@ class AircraftRouteFollower:
|
||||
speed_mps = speed_kmh * 1000.0 / 3600.0 # 转换为米/秒
|
||||
move_distance = speed_mps * elapsed_time
|
||||
|
||||
# 如果已经接近目标点(5米内),移动到下一个路径点
|
||||
if distance_to_target <= 5.0:
|
||||
self.current_point_index += 1
|
||||
self.route_progress = min(1.0, self.current_point_index / max(1, len(self.route_points) - 1))
|
||||
# 优化路径跟随:如果移动距离大于到目标点的距离,直接跳到下一个合适的点
|
||||
remaining_distance = move_distance
|
||||
|
||||
if self.current_point_index >= len(self.route_points):
|
||||
# 路径完成
|
||||
aircraft["latitude"] = target_lat
|
||||
aircraft["longitude"] = target_lon
|
||||
self.is_at_gate = (self.current_route_type == "arrival")
|
||||
logging.info(f"航空器 {self.flight_no} 完成 {self.current_route_type} 路径")
|
||||
return True
|
||||
while remaining_distance > 0 and self.current_point_index < len(self.route_points):
|
||||
# 如果已经接近目标点或剩余移动距离大于目标距离,移动到下一个路径点
|
||||
if distance_to_target <= remaining_distance:
|
||||
# 移动到当前目标点
|
||||
remaining_distance -= distance_to_target
|
||||
self.current_point_index += 1
|
||||
self.route_progress = min(1.0, self.current_point_index / max(1, len(self.route_points) - 1))
|
||||
|
||||
# 更新目标到下一个路径点
|
||||
target_lat, target_lon = self.route_points[self.current_point_index]
|
||||
distance_to_target = haversine_distance(current_lat, current_lon, target_lat, target_lon)
|
||||
if self.current_point_index >= len(self.route_points):
|
||||
# 路径完成,设置到真正的路径终点
|
||||
final_lat, final_lon = self.route_points[-1] # 路径的最后一个点
|
||||
aircraft["latitude"] = final_lat
|
||||
aircraft["longitude"] = final_lon
|
||||
self.is_at_gate = (self.current_route_type == "arrival")
|
||||
self.flight_status = 'at_gate' if self.is_at_gate else 'completed'
|
||||
# 设置5秒等待时间
|
||||
self.wait_until = current_time + self.waiting_duration
|
||||
logging.info(f"航空器 {self.flight_no} 完成 {self.current_route_type} 路径,等待{self.waiting_duration}秒后重新开始")
|
||||
return True
|
||||
|
||||
# 计算移动方向
|
||||
if distance_to_target > 0:
|
||||
# 计算移动比例
|
||||
move_ratio = min(1.0, move_distance / distance_to_target)
|
||||
# 更新到下一个目标点
|
||||
current_lat, current_lon = target_lat, target_lon # 当前位置更新为刚到达的点
|
||||
if self.current_point_index < len(self.route_points):
|
||||
target_lat, target_lon = self.route_points[self.current_point_index]
|
||||
distance_to_target = haversine_distance(current_lat, current_lon, target_lat, target_lon)
|
||||
else:
|
||||
# 已经超出路径范围,跳出循环
|
||||
break
|
||||
else:
|
||||
# 不能完全到达目标点,按比例移动
|
||||
break
|
||||
|
||||
# 计算最终位置
|
||||
if remaining_distance > 0 and distance_to_target > 0:
|
||||
# 按比例移动到目标点
|
||||
move_ratio = remaining_distance / distance_to_target
|
||||
|
||||
# 线性插值计算新位置
|
||||
new_lat = current_lat + (target_lat - current_lat) * move_ratio
|
||||
@ -1523,6 +1549,10 @@ class AircraftRouteFollower:
|
||||
# 更新航空器位置
|
||||
aircraft["latitude"] = new_lat
|
||||
aircraft["longitude"] = new_lon
|
||||
else:
|
||||
# 已到达当前目标点,更新位置
|
||||
aircraft["latitude"] = current_lat
|
||||
aircraft["longitude"] = current_lon
|
||||
|
||||
return False
|
||||
|
||||
@ -1583,40 +1613,40 @@ class AircraftRouteManager:
|
||||
def _update_arrival_only_aircraft(self, aircraft: dict[str, Any], follower: AircraftRouteFollower,
|
||||
speed: float, elapsed_time: float):
|
||||
"""更新纯进港模式飞机位置"""
|
||||
if follower.current_route_type != "arrival":
|
||||
current_time = time.time()
|
||||
|
||||
# 检查是否需要开始新路径(等待期结束后或初始状态)
|
||||
if follower.flight_status in ['idle', 'completed', 'at_gate', 'waiting'] and current_time >= follower.wait_until:
|
||||
follower.start_route("arrival")
|
||||
# 设置到进港路径起点
|
||||
if follower.route_points:
|
||||
aircraft["latitude"] = follower.route_points[0][0]
|
||||
aircraft["longitude"] = follower.route_points[0][1]
|
||||
logging.info(f"航空器 {aircraft.get('flightNo')} 等待结束,重新开始进港路径")
|
||||
|
||||
route_completed = follower.update_position_on_route(aircraft, speed, elapsed_time)
|
||||
if route_completed:
|
||||
# 进港完成后重新开始,立即跳转到起点
|
||||
follower.start_route("arrival")
|
||||
if follower.route_points:
|
||||
aircraft["latitude"] = follower.route_points[0][0]
|
||||
aircraft["longitude"] = follower.route_points[0][1]
|
||||
logging.info(f"航空器 {aircraft.get('flightNo')} 进港完成,重新开始从起点: ({follower.route_points[0][0]:.6f}, {follower.route_points[0][1]:.6f})")
|
||||
if route_completed and follower.flight_status != 'waiting':
|
||||
# 路径完成,已设置5秒等待时间,无需立即重新开始
|
||||
logging.info(f"航空器 {aircraft.get('flightNo')} 进港完成,将等待{follower.waiting_duration}秒后重新开始")
|
||||
|
||||
def _update_departure_only_aircraft(self, aircraft: dict[str, Any], follower: AircraftRouteFollower,
|
||||
speed: float, elapsed_time: float):
|
||||
"""更新纯出港模式飞机位置"""
|
||||
if follower.current_route_type != "departure":
|
||||
current_time = time.time()
|
||||
|
||||
# 检查是否需要开始新路径(等待期结束后或初始状态)
|
||||
if follower.flight_status in ['idle', 'completed', 'at_gate', 'waiting'] and current_time >= follower.wait_until:
|
||||
follower.start_route("departure")
|
||||
# 设置到出港路径起点
|
||||
if follower.route_points:
|
||||
aircraft["latitude"] = follower.route_points[0][0]
|
||||
aircraft["longitude"] = follower.route_points[0][1]
|
||||
logging.info(f"航空器 {aircraft.get('flightNo')} 等待结束,重新开始出港路径")
|
||||
|
||||
route_completed = follower.update_position_on_route(aircraft, speed, elapsed_time)
|
||||
if route_completed:
|
||||
# 出港完成后重新开始,立即跳转到起点
|
||||
follower.start_route("departure")
|
||||
if follower.route_points:
|
||||
aircraft["latitude"] = follower.route_points[0][0]
|
||||
aircraft["longitude"] = follower.route_points[0][1]
|
||||
logging.info(f"航空器 {aircraft.get('flightNo')} 出港完成,重新开始从起点: ({follower.route_points[0][0]:.6f}, {follower.route_points[0][1]:.6f})")
|
||||
if route_completed and follower.flight_status != 'waiting':
|
||||
# 路径完成,已设置5秒等待时间,无需立即重新开始
|
||||
logging.info(f"航空器 {aircraft.get('flightNo')} 出港完成,将等待{follower.waiting_duration}秒后重新开始")
|
||||
|
||||
|
||||
# 创建全局路径跟随管理器
|
||||
@ -2327,65 +2357,37 @@ def get_departure_taxiway_route():
|
||||
})
|
||||
|
||||
def get_active_flights() -> list[dict[str, Any]]:
|
||||
"""获取当前活跃的进出港航班(简化版)"""
|
||||
current_time = time.time()
|
||||
"""获取当前活跃的进出港航班(基于路径状态)"""
|
||||
active_flights = []
|
||||
current_time = int(time.time() * 1000)
|
||||
|
||||
for flight_no, flight_info in flight_data.items():
|
||||
# 安全读取并转换为数值
|
||||
cycle_start = to_float_safe(flight_info.get("cycle_start"))
|
||||
active_duration = to_float_safe(flight_info.get("active_duration"))
|
||||
gap_duration = to_float_safe(flight_info.get("gap_duration"))
|
||||
|
||||
# 兜底默认值
|
||||
if cycle_start is None:
|
||||
cycle_start = current_time
|
||||
if active_duration is None or active_duration <= 0:
|
||||
active_duration = 600.0
|
||||
if gap_duration is None or gap_duration < 0:
|
||||
gap_duration = 10.0
|
||||
|
||||
# 计算从周期开始的时间与总周期
|
||||
elapsed_time = float(current_time) - float(cycle_start)
|
||||
total_cycle = float(active_duration) + float(gap_duration)
|
||||
|
||||
# 避免除零
|
||||
if total_cycle <= 0:
|
||||
total_cycle = float(active_duration) if active_duration > 0 else 1.0
|
||||
|
||||
# 计算在当前周期中的位置
|
||||
cycle_position = float(elapsed_time) % float(total_cycle)
|
||||
|
||||
# 检查是否在活跃期内
|
||||
if cycle_position <= float(active_duration):
|
||||
# 在活跃期内,根据航班类型返回信息
|
||||
flight_type = flight_info.get("type")
|
||||
# 遍历所有路径跟随管理器中的飞机
|
||||
for flight_no, follower in route_manager.followers.items():
|
||||
# 检查飞机是否在活跃状态(正在路径中或在机位)
|
||||
if follower.flight_status in ['in_route', 'at_gate']:
|
||||
# 获取航班基础信息
|
||||
if flight_no in flight_data:
|
||||
flight_info = flight_data[flight_no]
|
||||
|
||||
# 航班使用固定信息
|
||||
flight_data_response = {
|
||||
"flightNo": flight_info.get("flightNo"),
|
||||
"type": flight_type,
|
||||
"runway": flight_info.get("runway"),
|
||||
"contactCross": flight_info.get("contactCross"),
|
||||
"seat": flight_info.get("seat"),
|
||||
"time": flight_info.get("fixed_time") # 使用固定时间
|
||||
}
|
||||
active_flights.append(flight_data_response)
|
||||
# 根据路径类型确定航班通知类型
|
||||
flight_type = flight_info.get("type")
|
||||
event_type = "落地" if flight_type == "IN" else "滑出"
|
||||
|
||||
# 构造航班通知数据
|
||||
flight_notification = {
|
||||
"flightNo": flight_no,
|
||||
"type": flight_type,
|
||||
"runway": flight_info.get("runway"),
|
||||
"contactCross": flight_info.get("contactCross"),
|
||||
"seat": flight_info.get("seat"),
|
||||
"time": current_time
|
||||
}
|
||||
active_flights.append(flight_notification)
|
||||
|
||||
logging.info(f"航班 {flight_no} {event_type}通知中 (路径状态: {follower.flight_status}, 进度: {follower.route_progress:.2f})")
|
||||
else:
|
||||
logging.warning(f"航班 {flight_no} 在路径跟随器中但不在flight_data中")
|
||||
|
||||
# 确定事件类型用于日志
|
||||
actual_type = flight_data_response.get("type", flight_info.get("type"))
|
||||
event_type = "落地" if actual_type == "IN" else "滑出"
|
||||
logging.info(f"航班 {flight_no} {event_type}通知中 (活跃期: {cycle_position:.1f}s/{int(active_duration)}s)")
|
||||
else:
|
||||
# 在间隔期内,更新固定时间为下一个周期
|
||||
cycle_number = int(float(elapsed_time) // float(total_cycle)) + 1
|
||||
next_cycle_start = float(cycle_start) + cycle_number * float(total_cycle)
|
||||
# 简化时间计算,与路径起点时间同步
|
||||
flight_info["fixed_time"] = int(next_cycle_start * 1000) # 使用周期开始时间作为通知时间
|
||||
|
||||
gap_part = cycle_position - float(active_duration)
|
||||
logging.info(f"航班 {flight_no} 在间隔期,准备下一个周期 (间隔期: {gap_part:.1f}s/{int(gap_duration)}s)")
|
||||
|
||||
return active_flights
|
||||
|
||||
@app.route('/openApi/getInboundAndOutboundFlightsNotification', methods=['GET', 'OPTIONS'])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user