const SCRIPT = "/home/ztl/LJ360/bash/video_tool.sh"; const SERVICE = "lj360_camera"; const LOG_FILE = "/home/ztl/LJ360/lj360_camera_keepalive.log"; const WEBPY = "/home/ztl/LJ360/web.py"; // DOM 元素 let statusIcon, statusText, outputBox, autostartSwitch; function initElements() { statusIcon = document.getElementById("status-icon"); statusText = document.getElementById("status-text"); outputBox = document.getElementById("output"); autostartSwitch = document.getElementById("autostart-switch"); } function setOutput(text) { if (outputBox) { outputBox.textContent = text; outputBox.scrollTop = outputBox.scrollHeight; } } function setStatus(text, isActive) { if (statusText) { statusText.textContent = text; } const panel = document.getElementById("status-panel"); if (panel) { // 移除现有状态类 panel.classList.remove("status-success", "status-danger", "status-warning"); if (isActive === true) { panel.classList.add("status-success"); } else if (isActive === false) { panel.classList.add("status-danger"); } else if (isActive === undefined) { panel.classList.add("status-warning"); } } if (statusIcon) { if (isActive === true) { statusIcon.innerHTML = ''; } else if (isActive === false) { statusIcon.innerHTML = ''; } else { statusIcon.innerHTML = ''; } } } function runCommand(args, callback) { const proc = cockpit.spawn(args, { superuser: "require", err: "out" }); let output = ""; proc.stream(data => { output += data; }); proc.then(() => callback(output, null)); proc.catch(err => callback(output, err)); } // 获取服务状态和开机自启状态 function refreshStatus() { setStatus("正在获取服务状态...", undefined); setOutput("⏳ 正在刷新状态..."); // 获取服务运行状态 runCommand(["systemctl", "is-active", SERVICE + ".service"], (outActive, errActive) => { const isRunning = (outActive.trim() === "active"); // 获取开机自启状态 runCommand(["systemctl", "is-enabled", SERVICE + ".service"], (outEnabled, errEnabled) => { let isEnabled = false; if (!errEnabled) { const enabledOut = outEnabled.trim(); isEnabled = (enabledOut === "enabled" || enabledOut === "static"); } // 更新开关状态(不触发change事件) if (autostartSwitch) { autostartSwitch.checked = isEnabled; } // 更新状态文本 if (isRunning) { setStatus("服务正在运行" + (isEnabled ? " (开机自启已启用)" : " (开机自启未启用)"), true); } else { setStatus("服务未运行" + (isEnabled ? " (开机自启已启用但未运行)" : " (开机自启未启用)"), false); } // 获取详细状态输出 runCommand(["systemctl", "status", SERVICE + ".service", "--no-pager", "-l"], (outDetail) => { setOutput(outDetail || "无状态信息"); }); }); }); } // 设置开机自启(通过开关) function setAutostart(enabled) { setOutput("⏳ " + (enabled ? "正在启用开机自启..." : "正在禁用开机自启...")); const action = enabled ? "enable_autostart" : "disable_autostart"; runCommand(["bash", SCRIPT, action], (out, err) => { if (err) { setOutput("❌ 错误: " + (err.message || err) + "\n" + (out || "")); // 恢复开关状态 setTimeout(() => refreshStatus(), 500); } else { setOutput((enabled ? "✅ 开机自启已启用" : "✅ 开机自启已禁用") + "\n" + (out || "")); setTimeout(() => refreshStatus(), 300); } }); } // 启动服务 function startService() { setOutput("⏳ 正在启动服务..."); runCommand(["systemctl", "start", SERVICE + ".service"], (out, err) => { if (err) { setOutput("❌ 启动失败: " + (err.message || err) + "\n" + out); } else { setOutput("✅ 服务已启动\n" + out); } setTimeout(() => refreshStatus(), 500); }); } // 停止服务 function stopService() { setOutput("⏳ 正在停止服务..."); runCommand(["systemctl", "stop", SERVICE + ".service"], (out, err) => { if (err) { setOutput("❌ 停止失败: " + (err.message || err) + "\n" + out); } else { setOutput("✅ 服务已停止\n" + out); } setTimeout(() => refreshStatus(), 500); }); } // 重启服务 function restartService() { setOutput("⏳ 正在重启服务..."); runCommand(["systemctl", "restart", SERVICE + ".service"], (out, err) => { if (err) { setOutput("❌ 重启失败: " + (err.message || err) + "\n" + out); } else { setOutput("✅ 服务已重启\n" + out); } setTimeout(() => refreshStatus(), 800); }); } // 查看日志 function viewLog() { setOutput("⏳ 读取日志文件..."); runCommand(["tail", "-n", "80", LOG_FILE], (out, err) => { if (err) { setOutput("❌ 无法读取日志: " + (err.message || err) + "\n尝试查看服务日志..."); // 备用:查看 journalctl runCommand(["journalctl", "-u", SERVICE + ".service", "-n", "50", "--no-pager"], (out2, err2) => { if (err2) { setOutput("📭 日志为空或无法读取\n" + (out2 || "")); } else { setOutput("📋 系统日志 (journalctl):\n" + (out2 || "无日志")); } }); } else { setOutput("📋 服务日志 (最近80行):\n" + (out || "日志为空")); } }); } // 单独启动 web.py function startWebPy() { setOutput("⏳ 正在启动 web.py..."); runCommand([ "bash", "-c", "export DISPLAY=:0 && cd /home/ztl/LJ360 && sudo -u ztl python3 /home/ztl/LJ360/web.py >> /home/ztl/LJ360/web.log 2>&1 &" ], (out, err) => { if (err) { setOutput("❌ 启动 web.py 失败: " + (err.message || err)); } else { setOutput("✅ web.py 已在后台启动\n可通过 'ps aux | grep web.py' 查看进程"); } }); } // 停止 web.py function stopWebPy() { setOutput("⏳ 正在关闭 web.py..."); runCommand(["bash", "-c", "pkill -f /home/ztl/LJ360/web.py"], (out, err) => { if (err) { // pkill 没有找到进程也会返回错误,这是正常的 if (err.message && err.message.includes("exit code 1")) { setOutput("⚠️ 未找到运行中的 web.py 进程"); } else { setOutput("❌ 关闭失败: " + (err.message || err)); } } else { setOutput("✅ web.py 已关闭"); } }); } // 事件绑定 function bindEvents() { const btnStart = document.getElementById("btn-start"); const btnStop = document.getElementById("btn-stop"); const btnRestart = document.getElementById("btn-restart"); const btnStatus = document.getElementById("btn-status"); const btnLog = document.getElementById("btn-log"); const btnPyon = document.getElementById("btn-pyon"); const btnPyoff = document.getElementById("btn-pyoff"); if (btnStart) btnStart.addEventListener("click", startService); if (btnStop) btnStop.addEventListener("click", stopService); if (btnRestart) btnRestart.addEventListener("click", restartService); if (btnStatus) btnStatus.addEventListener("click", refreshStatus); if (btnLog) btnLog.addEventListener("click", viewLog); if (btnPyon) btnPyon.addEventListener("click", startWebPy); if (btnPyoff) btnPyoff.addEventListener("click", stopWebPy); // 开关事件:开机自启变更 if (autostartSwitch) { autostartSwitch.addEventListener("change", function(e) { setAutostart(e.target.checked); }); } } // 页面初始化 document.addEventListener("DOMContentLoaded", function() { initElements(); bindEvents(); refreshStatus(); });