|
|
|
|
@ -4,8 +4,7 @@ from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout
|
|
|
|
|
QWidget, QLabel, QSplitter, QScrollArea,
|
|
|
|
|
QSizePolicy, QTabWidget, QTableWidget, QTableWidgetItem,
|
|
|
|
|
QHeaderView, QPushButton, QCheckBox, QLineEdit,
|
|
|
|
|
QComboBox, QDialog, QPlainTextEdit, QSlider,
|
|
|
|
|
QMessageBox)
|
|
|
|
|
QComboBox, QDialog, QPlainTextEdit, QSlider)
|
|
|
|
|
from PyQt6.QtCore import Qt, QTimer, QObject, pyqtSignal, QEvent, QPropertyAnimation, pyqtProperty, QEasingCurve
|
|
|
|
|
from PyQt6.QtGui import QColor, QFont, QPainter, QPen
|
|
|
|
|
import sys
|
|
|
|
|
@ -148,7 +147,7 @@ class ToggleSwitch(QWidget):
|
|
|
|
|
class ControlStationUI(QMainWindow):
|
|
|
|
|
planning_finished = pyqtSignal(object)
|
|
|
|
|
|
|
|
|
|
VERSION = '2.5.0'
|
|
|
|
|
VERSION = '2.4.1'
|
|
|
|
|
FONT_SCALE_MIN = 70
|
|
|
|
|
FONT_SCALE_MAX = 180
|
|
|
|
|
FONT_SCALE_DEFAULT = 100
|
|
|
|
|
@ -1103,7 +1102,6 @@ class ControlStationUI(QMainWindow):
|
|
|
|
|
panel.mode_change_requested.connect(self._handle_group_mode_change)
|
|
|
|
|
panel.arm_requested.connect(self._handle_group_arm)
|
|
|
|
|
panel.takeoff_requested.connect(self._handle_group_takeoff)
|
|
|
|
|
panel.reboot_requested.connect(self._handle_group_reboot)
|
|
|
|
|
panel.box_select_requested.connect(self._handle_box_select)
|
|
|
|
|
panel.select_all_requested.connect(self._handle_select_all_for_group)
|
|
|
|
|
panel.clear_group_requested.connect(self._handle_clear_group)
|
|
|
|
|
@ -1428,39 +1426,6 @@ class ControlStationUI(QMainWindow):
|
|
|
|
|
future = self.monitor.takeoff_drone(drone_id, altitude)
|
|
|
|
|
loop.create_task(self.handle_service_response(future, f"起飛 {drone_id} ({altitude}m)"))
|
|
|
|
|
|
|
|
|
|
def _handle_group_reboot(self, group_id):
|
|
|
|
|
"""重啟群組內所有選中的飛控。"""
|
|
|
|
|
group = self.mission_groups.get(group_id)
|
|
|
|
|
if not group:
|
|
|
|
|
_log("WARN", f"找不到群組: {group_id}")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
selected = list(group.selected_drone_ids)
|
|
|
|
|
if not selected:
|
|
|
|
|
self.statusBar().showMessage(f"群組 {group_id} 中沒有無人機", 3000)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
reply = QMessageBox.warning(
|
|
|
|
|
self,
|
|
|
|
|
"確認重啟飛控",
|
|
|
|
|
f"即將透過 command long 重啟 Group {group_id} 的 {len(selected)} 台飛控:\n"
|
|
|
|
|
f"{', '.join(selected)}\n\n"
|
|
|
|
|
"這會中斷飛控連線,請確認無人機已在安全狀態。",
|
|
|
|
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
|
|
|
|
QMessageBox.StandardButton.No,
|
|
|
|
|
)
|
|
|
|
|
if reply != QMessageBox.StandardButton.Yes:
|
|
|
|
|
_log("WARN", f"Group {group_id} 飛控重啟已取消")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
_log("INFO", f"Group {group_id} 批次重啟飛控: {', '.join(selected)}")
|
|
|
|
|
self.statusBar().showMessage(f"Group {group_id}: 正在送出重啟命令", 3000)
|
|
|
|
|
|
|
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
|
for drone_id in selected:
|
|
|
|
|
future = self.monitor.reboot_drone(drone_id)
|
|
|
|
|
loop.create_task(self.handle_service_response(future, f"重啟飛控 {drone_id}"))
|
|
|
|
|
|
|
|
|
|
def _handle_box_select(self, group_id):
|
|
|
|
|
"""觸發地圖框選 → 框選完成後直接分配到該群組"""
|
|
|
|
|
self._pending_box_assign = group_id
|
|
|
|
|
|