터치 패널 사이드바 축소와 팬 표시 오류 수정
This commit is contained in:
1 parent
5bfac4429a
commit
e99fe1021a
2 files changed
+103
-43
No files matched your search
@@ -4,6 +4,68 @@ declare(strict_types=1);
|
||||
define('CONTROL_API_LIBRARY', true);
|
||||
require_once __DIR__ . '/../public/api.php';
|
||||
|
||||
function touch_panel_snapshot(array $snapshot): array
|
||||
{
|
||||
$network = is_array($snapshot['network'] ?? null) ? $snapshot['network'] : [];
|
||||
$wifi = is_array($snapshot['wifi'] ?? null) ? $snapshot['wifi'] : [];
|
||||
$system = is_array($snapshot['system'] ?? null) ? $snapshot['system'] : [];
|
||||
$fan = is_array($snapshot['fan'] ?? null) ? $snapshot['fan'] : [];
|
||||
$touch = is_array($snapshot['touch_display'] ?? null) ? $snapshot['touch_display'] : [];
|
||||
|
||||
$interfaces = [];
|
||||
foreach (($network['interfaces'] ?? []) as $row) {
|
||||
if (!is_array($row) || !isset($row['name'])) {
|
||||
continue;
|
||||
}
|
||||
$interfaces[] = [
|
||||
'name' => $row['name'],
|
||||
'state' => $row['state'] ?? null,
|
||||
'carrier' => $row['carrier'] ?? null,
|
||||
'rx_errors' => $row['rx_errors'] ?? 0,
|
||||
'tx_errors' => $row['tx_errors'] ?? 0,
|
||||
'rx_dropped' => $row['rx_dropped'] ?? 0,
|
||||
'tx_dropped' => $row['tx_dropped'] ?? 0,
|
||||
];
|
||||
}
|
||||
|
||||
$clients = [];
|
||||
foreach (($wifi['clients'] ?? []) as $client) {
|
||||
if (!is_array($client)) {
|
||||
continue;
|
||||
}
|
||||
$clients[] = [
|
||||
'band' => $client['band'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'ok' => (bool)($snapshot['ok'] ?? true),
|
||||
'generated_at' => $snapshot['generated_at'] ?? null,
|
||||
'fan' => [
|
||||
'mode' => $fan['mode'] ?? 'auto',
|
||||
'pwm' => $fan['pwm'] ?? 0,
|
||||
'percent' => $fan['percent'] ?? 0,
|
||||
'rpm' => $fan['rpm'] ?? 0,
|
||||
'control_temp_c' => $fan['control_temp_c'] ?? null,
|
||||
'policy_ok' => $fan['policy_ok'] ?? true,
|
||||
],
|
||||
'system' => [
|
||||
'hostname' => $system['hostname'] ?? null,
|
||||
'temp_c' => $system['temp_c'] ?? null,
|
||||
],
|
||||
'network' => [
|
||||
'default_interface' => $network['default_interface'] ?? null,
|
||||
'interfaces' => $interfaces,
|
||||
],
|
||||
'wifi' => [
|
||||
'clients' => $clients,
|
||||
],
|
||||
'touch_display' => [
|
||||
'connected' => $touch['connected'] ?? false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function touch_panel_json(array $payload, int $code = 0): never
|
||||
{
|
||||
fwrite(STDOUT, json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL);
|
||||
@@ -16,7 +78,7 @@ try {
|
||||
if ($command === 'status') {
|
||||
touch_panel_json([
|
||||
'ok' => true,
|
||||
'data' => collect_snapshot(false),
|
||||
'data' => touch_panel_snapshot(collect_snapshot(false)),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -41,7 +103,7 @@ try {
|
||||
|
||||
touch_panel_json([
|
||||
'ok' => true,
|
||||
'data' => collect_snapshot(false),
|
||||
'data' => touch_panel_snapshot(collect_snapshot(false)),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
+39
-41
@@ -9,7 +9,6 @@ from PyQt5.QtGui import QColor, QFont, QPainter
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication,
|
||||
QFrame,
|
||||
QGridLayout,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QMainWindow,
|
||||
@@ -49,7 +48,7 @@ class StatusDot(QWidget):
|
||||
self.active = False
|
||||
self.warning = False
|
||||
self.pulse = 0
|
||||
self.setFixedSize(34, 34)
|
||||
self.setFixedSize(22, 22)
|
||||
|
||||
def set_state(self, active, warning=False):
|
||||
self.active = active
|
||||
@@ -73,9 +72,9 @@ class StatusDot(QWidget):
|
||||
base = QColor("#86efac") if self.pulse % 2 == 0 else QColor("#16a34a")
|
||||
painter.setBrush(base)
|
||||
painter.setPen(Qt.NoPen)
|
||||
painter.drawEllipse(4, 4, 26, 26)
|
||||
painter.drawEllipse(3, 3, 16, 16)
|
||||
painter.setBrush(QColor(255, 255, 255, 55))
|
||||
painter.drawEllipse(10, 8, 8, 8)
|
||||
painter.drawEllipse(8, 6, 5, 5)
|
||||
|
||||
|
||||
class StatusTile(QFrame):
|
||||
@@ -88,16 +87,20 @@ class StatusTile(QFrame):
|
||||
self.detail.setObjectName("statusDetail")
|
||||
self.detail.setWordWrap(True)
|
||||
|
||||
self.detail.setAlignment(Qt.AlignCenter)
|
||||
self.detail.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
self.setFixedHeight(58)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(8, 7, 8, 8)
|
||||
layout.setSpacing(4)
|
||||
layout.addWidget(self.title, 0, Qt.AlignLeft)
|
||||
layout.addStretch(1)
|
||||
layout.addWidget(self.dot, 0, Qt.AlignCenter)
|
||||
layout.addStretch(1)
|
||||
layout.addWidget(self.detail)
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(7, 6, 7, 6)
|
||||
layout.setSpacing(6)
|
||||
layout.addWidget(self.dot, 0, Qt.AlignLeft | Qt.AlignVCenter)
|
||||
|
||||
text_layout = QVBoxLayout()
|
||||
text_layout.setContentsMargins(0, 0, 0, 0)
|
||||
text_layout.setSpacing(1)
|
||||
text_layout.addWidget(self.title)
|
||||
text_layout.addWidget(self.detail)
|
||||
layout.addLayout(text_layout, 1)
|
||||
self.setObjectName("statusTile")
|
||||
|
||||
def update_state(self, active, detail, warning=False):
|
||||
@@ -140,35 +143,31 @@ class TouchPanel(QMainWindow):
|
||||
|
||||
def _build_ui(self):
|
||||
root = QWidget()
|
||||
grid = QGridLayout(root)
|
||||
grid.setContentsMargins(16, 14, 16, 14)
|
||||
grid.setHorizontalSpacing(14)
|
||||
grid.setVerticalSpacing(10)
|
||||
layout = QHBoxLayout(root)
|
||||
layout.setContentsMargins(4, 8, 10, 8)
|
||||
layout.setSpacing(8)
|
||||
|
||||
left = QFrame()
|
||||
left.setObjectName("panel")
|
||||
left.setObjectName("statusPanel")
|
||||
left.setFixedWidth(132)
|
||||
left_layout = QVBoxLayout(left)
|
||||
left_layout.setContentsMargins(14, 14, 14, 14)
|
||||
left_layout.setSpacing(8)
|
||||
left_layout.setContentsMargins(6, 8, 6, 8)
|
||||
left_layout.setSpacing(6)
|
||||
|
||||
title = QLabel("상태")
|
||||
title.setObjectName("sectionTitle")
|
||||
left_layout.addWidget(title)
|
||||
|
||||
status_grid = QGridLayout()
|
||||
status_grid.setHorizontalSpacing(8)
|
||||
status_grid.setVerticalSpacing(8)
|
||||
for index, (key, label) in enumerate([
|
||||
for key, label in [
|
||||
("io", "IO"),
|
||||
("wan", "WAN"),
|
||||
("lan", "LAN"),
|
||||
("wifi24", "2.4G"),
|
||||
("wifi5", "5G"),
|
||||
]):
|
||||
]:
|
||||
row = StatusTile(label)
|
||||
self.rows[key] = row
|
||||
status_grid.addWidget(row, index // 2, index % 2)
|
||||
left_layout.addLayout(status_grid, 1)
|
||||
left_layout.addWidget(row)
|
||||
left_layout.addStretch(1)
|
||||
|
||||
right = QFrame()
|
||||
@@ -228,10 +227,8 @@ class TouchPanel(QMainWindow):
|
||||
right_layout.addWidget(self.notice)
|
||||
right_layout.addStretch(1)
|
||||
|
||||
grid.addWidget(left, 0, 0)
|
||||
grid.addWidget(right, 0, 1)
|
||||
grid.setColumnStretch(0, 3)
|
||||
grid.setColumnStretch(1, 4)
|
||||
layout.addWidget(left)
|
||||
layout.addWidget(right, 1)
|
||||
self.setCentralWidget(root)
|
||||
|
||||
def tick_pulses(self):
|
||||
@@ -295,12 +292,12 @@ class TouchPanel(QMainWindow):
|
||||
w5 = interfaces.get("wlan1") or {}
|
||||
|
||||
io_active = bool(touch.get("connected")) and bool(fan.get("policy_ok", True))
|
||||
io_detail = f"{system.get('hostname', '-')} / {temp:.1f} C"
|
||||
io_detail = f"{temp:.1f} C"
|
||||
self.rows["io"].update_state(io_active, io_detail, temp >= 75)
|
||||
self.rows["wan"].update_state(self.iface_up(wan), self.iface_detail(wan), self.iface_warn(wan))
|
||||
self.rows["lan"].update_state(self.iface_up(lan), f"{len(lan_clients)}대 / {self.iface_detail(lan)}", self.iface_warn(lan))
|
||||
self.rows["wifi24"].update_state(self.iface_up(w24), f"{len(wifi24)}대 / {self.iface_detail(w24)}", self.iface_warn(w24))
|
||||
self.rows["wifi5"].update_state(self.iface_up(w5), f"{len(wifi5)}대 / {self.iface_detail(w5)}", self.iface_warn(w5))
|
||||
self.rows["lan"].update_state(self.iface_up(lan), f"{len(lan_clients)}대 {self.iface_detail(lan)}", self.iface_warn(lan))
|
||||
self.rows["wifi24"].update_state(self.iface_up(w24), f"{len(wifi24)}대 {self.iface_detail(w24)}", self.iface_warn(w24))
|
||||
self.rows["wifi5"].update_state(self.iface_up(w5), f"{len(wifi5)}대 {self.iface_detail(w5)}", self.iface_warn(w5))
|
||||
|
||||
self.current_mode = mode
|
||||
self.current_pwm = pwm
|
||||
@@ -328,7 +325,7 @@ class TouchPanel(QMainWindow):
|
||||
return "없음"
|
||||
rx_drop = int(row.get("rx_dropped") or 0)
|
||||
tx_drop = int(row.get("tx_dropped") or 0)
|
||||
return f"{row.get('name', '-')} {row.get('state', '-')} / drop {rx_drop + tx_drop}"
|
||||
return f"{row.get('state', '-')} D{rx_drop + tx_drop}"
|
||||
|
||||
|
||||
def main():
|
||||
@@ -336,12 +333,13 @@ def main():
|
||||
app.setStyleSheet(
|
||||
"""
|
||||
QWidget { background: #0b1220; color: #e5edf7; font-family: "Noto Sans CJK KR", "Noto Sans KR", sans-serif; }
|
||||
#panel { background: #111a2e; border: 1px solid #27364f; border-radius: 18px; }
|
||||
#sectionTitle { font-size: 24px; font-weight: 700; }
|
||||
#panel { background: #111a2e; border: 1px solid #27364f; border-radius: 16px; }
|
||||
#statusPanel { background: #101827; border-right: 1px solid #263650; }
|
||||
#sectionTitle { font-size: 20px; font-weight: 700; }
|
||||
#statusTile { background: #d7d9dc; border: 2px groove #f4f4f4; border-radius: 2px; }
|
||||
#statusTitle { font-size: 15px; font-weight: 700; color: #111827; background: transparent; }
|
||||
#statusDetail { font-size: 11px; color: #475569; background: transparent; }
|
||||
#bigValue { font-size: 56px; font-weight: 800; color: #f8fafc; }
|
||||
#statusTitle { font-size: 13px; font-weight: 700; color: #111827; background: transparent; }
|
||||
#statusDetail { font-size: 10px; color: #475569; background: transparent; }
|
||||
#bigValue { font-size: 62px; font-weight: 800; color: #f8fafc; }
|
||||
#subValue { font-size: 22px; color: #b8c5d8; }
|
||||
#clock { font-size: 18px; color: #8fb3ff; font-weight: 700; }
|
||||
#notice { padding: 10px; background: #17233a; border: 1px solid #2b3c59; border-radius: 12px; color: #a8b8d0; }
|
||||
|
||||
Reference in new issue
Block a user