You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
4.2 KiB
JavaScript

const state = {
result: null,
frequencies: null,
health: null,
};
function byId(id) {
return document.getElementById(id);
}
function fmt(value, digits = 6) {
if (value === null || value === undefined) return "-";
if (typeof value !== "number") return String(value);
return Number.isFinite(value) ? value.toFixed(digits) : String(value);
}
async function getJson(url) {
const res = await fetch(url);
const data = await res.json().catch(() => ({}));
if (!res.ok) {
throw new Error(data.error || data.status || `HTTP ${res.status}`);
}
return data;
}
async function postJson(url, payload) {
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
throw new Error(data.error || data.status || `HTTP ${res.status}`);
}
return data;
}
function render() {
const data = state.result?.data;
const delivery = state.result?.output_delivery || state.frequencies?.output_delivery;
byId("updated-at").textContent = `updated: ${state.result?.updated_at_utc || "n/a"}`;
byId("health-status").textContent = `health: ${state.health?.status || "n/a"}`;
byId("delivery-status").textContent = `delivery: ${delivery?.status || "n/a"}`;
if (!data) {
byId("selected-freq").textContent = "-";
byId("pos-x").textContent = "-";
byId("pos-y").textContent = "-";
byId("pos-z").textContent = "-";
byId("rmse").textContent = "-";
byId("receivers-list").textContent = "Нет данных";
byId("delivery-details").textContent = JSON.stringify(delivery || {}, null, 2);
byId("freq-table").querySelector("tbody").innerHTML = "";
return;
}
byId("selected-freq").textContent = fmt(data.selected_frequency_hz, 1);
byId("pos-x").textContent = fmt(data.position?.x);
byId("pos-y").textContent = fmt(data.position?.y);
byId("pos-z").textContent = fmt(data.position?.z);
byId("rmse").textContent = fmt(data.rmse_m);
const receivers = data.receivers || [];
byId("receivers-list").textContent = JSON.stringify(receivers, null, 2);
byId("delivery-details").textContent = JSON.stringify(delivery || {}, null, 2);
const rows = data.frequency_table || [];
const tbody = byId("freq-table").querySelector("tbody");
tbody.innerHTML = rows
.map(
(row) => `
<tr>
<td>${fmt(row.frequency_hz, 1)}</td>
<td>${fmt(row.position?.x)}</td>
<td>${fmt(row.position?.y)}</td>
<td>${fmt(row.position?.z)}</td>
<td>${fmt(row.rmse_m)}</td>
<td>${row.exact ? "yes" : "no"}</td>
</tr>`
)
.join("");
}
async function loadAll() {
const [healthRes, resultRes, freqRes] = await Promise.allSettled([
getJson("/health"),
getJson("/result"),
getJson("/frequencies"),
]);
state.health = healthRes.status === "fulfilled" ? healthRes.value : { status: "error" };
state.result = resultRes.status === "fulfilled" ? resultRes.value : null;
state.frequencies = freqRes.status === "fulfilled" ? freqRes.value : null;
render();
}
async function refreshNow() {
await postJson("/refresh", {});
await loadAll();
}
async function loadConfig() {
try {
const config = await getJson("/config");
byId("config-editor").value = JSON.stringify(config.config, null, 2);
byId("config-state").textContent = "config: loaded";
} catch (err) {
byId("config-state").textContent = `config: ${err.message}`;
}
}
async function saveConfig() {
const raw = byId("config-editor").value.trim();
try {
const parsed = JSON.parse(raw);
const result = await postJson("/config", parsed);
byId("config-state").textContent = result.restart_required
? "config: saved, restart required"
: "config: saved";
} catch (err) {
byId("config-state").textContent = `config: ${err.message}`;
}
}
function bindUi() {
byId("refresh-now").addEventListener("click", refreshNow);
byId("load-config").addEventListener("click", loadConfig);
byId("save-config").addEventListener("click", saveConfig);
}
async function boot() {
bindUi();
await loadConfig();
await loadAll();
setInterval(loadAll, 2000);
}
boot().catch((err) => {
byId("health-status").textContent = `health: ${err.message}`;
});