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.

610 lines
30 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Панель Триангуляции</title>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
<link rel="stylesheet" href="/static/styles.css?v=20260312r5" />
</head>
<body>
<div class="bg-glow bg-glow-a"></div>
<div class="bg-glow bg-glow-b"></div>
<main id="app-shell" class="app-shell">
<aside id="side-nav" class="side-nav card">
<div class="nav-head">
<button id="menu-toggle" class="btn menu-toggle" type="button" aria-controls="menu-list" aria-expanded="true">Свернуть меню</button>
</div>
<div class="menu-wrap">
<div id="menu-list" class="menu-list">
<section class="menu-group" data-menu-group="monitoring">
<button
class="menu-group-toggle"
type="button"
data-menu-group-toggle="monitoring"
aria-controls="menu-group-monitoring"
aria-expanded="true"
>
<span class="menu-group-title">Мониторинг</span>
<span id="menu-badge-monitoring" class="menu-group-badge">н/д</span>
</button>
<div id="menu-group-monitoring" class="menu-group-body">
<button class="menu-item menu-item-active" data-section="overview" type="button">
<span class="menu-item-icon" aria-hidden="true">O</span>
<span class="menu-item-text">Обзор</span>
<span class="menu-item-note">Сводка</span>
</button>
<button class="menu-item" data-section="frequencies" type="button">
<span class="menu-item-icon" aria-hidden="true">F</span>
<span class="menu-item-text">Частоты</span>
<span class="menu-item-note">Таблица</span>
</button>
</div>
</section>
<section class="menu-group" data-menu-group="io">
<button
class="menu-group-toggle"
type="button"
data-menu-group-toggle="io"
aria-controls="menu-group-io"
aria-expanded="true"
>
<span class="menu-group-title">Потоки</span>
<span id="menu-badge-io" class="menu-group-badge">н/д</span>
</button>
<div id="menu-group-io" class="menu-group-body">
<button class="menu-item" data-section="io" type="button">
<span class="menu-item-icon" aria-hidden="true">I</span>
<span class="menu-item-text">Вход/Выход</span>
<span class="menu-item-note">Потоки</span>
</button>
<button class="menu-item" data-section="history" type="button">
<span class="menu-item-icon" aria-hidden="true">H</span>
<span class="menu-item-text">История</span>
<span class="menu-item-note">Лента</span>
</button>
</div>
</section>
<section class="menu-group" data-menu-group="config">
<button
class="menu-group-toggle"
type="button"
data-menu-group-toggle="config"
aria-controls="menu-group-config"
aria-expanded="true"
>
<span class="menu-group-title">Конфигурация</span>
<span id="menu-badge-config" class="menu-group-badge">н/д</span>
</button>
<div id="menu-group-config" class="menu-group-body">
<button class="menu-item" data-section="servers" type="button">
<span class="menu-item-icon" aria-hidden="true">S</span>
<span class="menu-item-text">Серверы</span>
<span class="menu-item-note">Настройка</span>
</button>
<button class="menu-item" data-section="json" type="button">
<span class="menu-item-icon" aria-hidden="true">{}</span>
<span class="menu-item-text">Конфигурация</span>
<span class="menu-item-note">JSON</span>
</button>
</div>
</section>
</div>
</div>
<div class="side-meta">
<div class="datetime-panel-controls">
<button
id="datetime-toggle"
class="btn btn-compact"
type="button"
aria-controls="meta-panel"
aria-expanded="true"
>
Скрыть служебную панель
</button>
<button id="density-toggle" class="btn btn-compact" type="button">Режим: детальный</button>
</div>
<div id="meta-panel" class="meta-panel">
<div id="date-time-panel" class="date-time-panel">
<span id="updated-date" class="meta-pill">дата: н/д</span>
<span id="updated-time" class="meta-pill">время: н/д</span>
</div>
<div class="status-panel">
<span id="health-status" class="meta-pill">сервис: н/д</span>
<span id="delivery-status" class="meta-pill">доставка: н/д</span>
</div>
<label class="timezone-picker">
<span>часовой пояс</span>
<select id="timezone-select"></select>
</label>
</div>
</div>
</aside>
<section class="content-area">
<section id="section-overview" class="panel panel-active">
<header class="hero card overview-hero">
<h2>Панель Радиопозиционирования</h2>
<p class="muted">Мониторинг и управление расчётом 3D триангуляции.</p>
<div class="hero-actions">
<button id="refresh-now" class="btn btn-primary">Обновить</button>
<button id="toggle-auto-refresh" class="btn" type="button">Пауза автообновления</button>
<label class="refresh-interval-control" for="auto-refresh-seconds">
<span>Интервал, с</span>
<input id="auto-refresh-seconds" type="number" min="1" max="120" step="1" value="2" />
</label>
<span id="refresh-state" class="badge badge-meta">автообновление: вкл (2с)</span>
</div>
</header>
<div class="overview-layout">
<article class="card overview-position-card">
<h2>Итоговая Позиция</h2>
<div class="result-box">
<div><span class="muted">Выбранная частота:</span> <b id="selected-freq">-</b></div>
<div><span class="muted">X:</span> <b id="pos-x">-</b></div>
<div><span class="muted">Y:</span> <b id="pos-y">-</b></div>
<div><span class="muted">Z:</span> <b id="pos-z">-</b></div>
<div><span class="muted">СКО (RMSE):</span> <b id="rmse">-</b></div>
</div>
</article>
<article class="card monitor-board overview-monitor-card">
<h2>Оперативный Мониторинг</h2>
<div class="monitor-headline">
<span class="io-chip io-chip-neutral">Сервис: <b id="ov-health-chip">н/д</b></span>
<span class="io-chip io-chip-neutral">Доставка: <b id="ov-delivery-chip">н/д</b></span>
<span class="io-chip io-chip-neutral">Обновлено: <b id="ov-updated-at">н/д</b></span>
</div>
<div class="monitor-grid">
<section class="monitor-panel monitor-kpi-panel">
<div class="overview-metrics">
<div class="metric-tile">
<span class="metric-title">Входы online</span>
<b id="ov-input-online" class="metric-value">0/0</b>
</div>
<div class="metric-tile">
<span class="metric-title">Выходы online</span>
<b id="ov-output-online" class="metric-value">0/0</b>
</div>
<div class="metric-tile">
<span class="metric-title">События в истории</span>
<b id="ov-history-total" class="metric-value">0</b>
</div>
<div class="metric-tile">
<span class="metric-title">Успех доставки</span>
<b id="ov-success-rate" class="metric-value">0%</b>
</div>
</div>
</section>
<section class="monitor-panel monitor-flow-panel">
<h3>Состояние Потоков</h3>
<div class="monitor-flow-row">
<span>Входные потоки</span>
<b id="ov-input-online-bar-text">0/0</b>
</div>
<div class="monitor-progress">
<span id="ov-input-online-bar" style="width:0%"></span>
</div>
<div class="monitor-flow-row">
<span>Выходные потоки</span>
<b id="ov-output-online-bar-text">0/0</b>
</div>
<div class="monitor-progress">
<span id="ov-output-online-bar" style="width:0%"></span>
</div>
<div class="monitor-flow-row">
<span>Успешная доставка</span>
<b id="ov-delivery-bar-text">0%</b>
</div>
<div class="monitor-progress monitor-progress-accent">
<span id="ov-delivery-bar" style="width:0%"></span>
</div>
</section>
</div>
</article>
</div>
</section>
<section id="section-frequencies" class="panel">
<article class="card">
<h2>Таблица По Частотам</h2>
<div class="table-wrap">
<table id="freq-table">
<thead>
<tr>
<th>Частота (МГц)</th>
<th>X</th>
<th>Y</th>
<th>Z</th>
<th>СКО (RMSE)</th>
<th>Точно</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</article>
<article class="card monitor-board">
<h2>Аналитика Частот</h2>
<div class="monitor-grid">
<section class="monitor-panel monitor-frequency-panel">
<h3>Профиль Частот</h3>
<div id="ov-frequency-health" class="frequency-health-list"></div>
</section>
<section class="monitor-panel monitor-topfreq-panel">
<h3>Лидеры Частот</h3>
<div id="ov-top-frequencies" class="top-frequencies"></div>
</section>
<section class="monitor-panel monitor-trends-panel">
<h3>Тренд Точности</h3>
<div class="trend-stack">
<article class="trend-card">
<div class="trend-head">
<span>RMSE, м</span>
<b id="ov-trend-rmse-meta">н/д</b>
</div>
<div id="ov-trend-rmse-chart" class="sparkline-wrap"></div>
</article>
</div>
</section>
</div>
</article>
</section>
<section id="section-io" class="panel">
<article class="card">
<h2>Входные И Выходные Данные</h2>
<p class="muted">Оперативный мониторинг входящих измерений и фактической отправки на выходные серверы.</p>
<div class="io-grid">
<section class="io-block">
<h3>Входные Данные (Ресиверы)</h3>
<div id="input-flow" class="io-list"></div>
</section>
<section class="io-block">
<h3>Выходные Данные (Отправка)</h3>
<div id="output-flow" class="io-list"></div>
</section>
</div>
<h3 class="io-history-title">Управление Тестовыми Сбоями</h3>
<div id="error-controls" class="io-list"></div>
</article>
<article class="card monitor-board">
<h2>Контур Входа/Выхода</h2>
<div class="monitor-grid">
<section class="monitor-panel monitor-signal-panel">
<h3>Сигналы Ресиверов</h3>
<div id="ov-signal-grid" class="signal-grid"></div>
</section>
<section class="monitor-panel monitor-stage-panel">
<h3>Контур Обработки</h3>
<div id="ov-pipeline-stages" class="pipeline-stages"></div>
</section>
<section class="monitor-panel monitor-trends-panel">
<h3>Тренды Потоков</h3>
<div class="trend-stack">
<article class="trend-card">
<div class="trend-head">
<span>Средний RSSI, дБм</span>
<b id="ov-trend-rssi-meta">н/д</b>
</div>
<div id="ov-trend-rssi-chart" class="sparkline-wrap"></div>
</article>
<article class="trend-card">
<div class="trend-head">
<span>Успех доставки, %</span>
<b id="ov-trend-delivery-meta">н/д</b>
</div>
<div id="ov-trend-delivery-chart" class="sparkline-wrap"></div>
</article>
</div>
</section>
</div>
</article>
</section>
<section id="section-history" class="panel">
<article class="card history-dashboard history-head-card">
<h2>История Входов И Выходов</h2>
<p class="muted">Связка входных измерений и отправки результата для отладки, SLA и диагностики ошибок.</p>
</article>
<div class="history-layout">
<article class="card history-data-card">
<h2>История И Фильтры</h2>
<div class="history-toolbar">
<label>
Статус
<select id="history-filter">
<option value="all">Все</option>
<option value="ok">Ок</option>
<option value="error">Ошибка</option>
<option value="partial">Частично</option>
<option value="skipped">Пропущено</option>
<option value="disabled">Отключено</option>
<option value="warming_up">Прогрев</option>
</select>
</label>
<div class="history-toolbar-right">
<label>
От (дата и время)
<input id="history-date-from" type="datetime-local" />
</label>
<label>
До (дата и время)
<input id="history-date-to" type="datetime-local" />
</label>
<label>
Страница
<select id="history-page-size">
<option value="10">10</option>
<option value="20">20</option>
<option value="50">50</option>
</select>
</label>
<div class="history-pager">
<button id="history-prev" class="btn" type="button">Назад</button>
<span id="history-page-info" class="badge badge-meta">Стр. 1/1 • 0 записей</span>
<button id="history-next" class="btn" type="button">Вперёд</button>
</div>
<button id="history-date-reset" class="btn" type="button">Сброс времени</button>
<button id="history-record-toggle" class="btn" type="button">Пауза записи</button>
<span id="history-record-state" class="badge badge-meta">запись: вкл</span>
<button id="clear-history" class="btn" type="button">Очистить историю</button>
</div>
</div>
<div class="table-wrap history-table-wrap">
<table id="io-history-table">
<thead>
<tr>
<th>Время</th>
<th>Частота (МГц)</th>
<th>Вход (RSSI/Радиусы)</th>
<th>Передано На Выход</th>
<th>Статус</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</article>
<article class="card history-monitor-card">
<h2>Мониторинг Истории</h2>
<div class="history-kpis">
<div class="kpi-card">
<span class="kpi-title">Событий</span>
<b id="hist-total" class="kpi-value">0</b>
</div>
<div class="kpi-card">
<span class="kpi-title">Успешно</span>
<b id="hist-ok" class="kpi-value">0</b>
</div>
<div class="kpi-card">
<span class="kpi-title">Проблемы</span>
<b id="hist-problem" class="kpi-value">0</b>
</div>
<div class="kpi-card">
<span class="kpi-title">Частот</span>
<b id="hist-freqs" class="kpi-value">0</b>
</div>
<div class="kpi-card">
<span class="kpi-title">Последнее событие</span>
<b id="hist-last" class="kpi-value">н/д</b>
</div>
</div>
<div class="history-insights">
<section class="insight-panel">
<h3>Диагностика Мониторинга</h3>
<div id="history-monitor" class="history-monitor"></div>
</section>
<section class="insight-panel">
<h3>Тренды Метрик</h3>
<div id="history-trends" class="history-trends"></div>
</section>
</div>
</article>
</div>
</section>
<section id="section-servers" class="panel">
<article class="card servers-head-card">
<h2>Настройка Серверов</h2>
<p class="muted">Доступы входа и выхода задаются отдельно. Общий фильтр входа автоматически применяется ко всем входным серверам.</p>
</article>
<div class="servers-layout servers-layout-modern">
<article class="card servers-card servers-card-modern">
<div class="server-card-head">
<h3 class="servers-title">Входные Серверы</h3>
<p class="muted">Управление ресиверами и их геометрией.</p>
</div>
<div class="server-card-body">
<div class="selector-row">
<label class="field-control">
<span class="field-label">Активный вход</span>
<select id="receiver-select"></select>
</label>
<span id="receiver-count" class="badge badge-meta chip-counter">входов: 0</span>
</div>
<div class="action-group">
<button id="add-receiver" class="btn" type="button">Добавить вход</button>
<button id="remove-receiver" class="btn" type="button">Удалить вход</button>
</div>
<div class="field-grid field-grid-2">
<label class="field-control">
<span class="field-label">Имя ресивера</span>
<input id="rx-id" type="text" placeholder="rx_north" />
</label>
<label class="field-control">
<span class="field-label">Адрес сервера (URL)</span>
<input id="rx-url" type="text" placeholder="http://receiver-r0:9000/data" />
</label>
</div>
<label class="field-control">
<span class="field-label">Частоты ресивера, МГц</span>
<input id="rx-frequencies" type="text" placeholder="433.92, 868.1, 915.0" />
<span class="field-hint">Укажите через запятую только рабочие частоты этого входа.</span>
</label>
<div class="field-grid field-grid-3">
<label class="field-control">
<span class="field-label">Координата X</span>
<input id="rx-center-x" type="number" step="0.001" />
</label>
<label class="field-control">
<span class="field-label">Координата Y</span>
<input id="rx-center-y" type="number" step="0.001" />
</label>
<label class="field-control">
<span class="field-label">Координата Z</span>
<input id="rx-center-z" type="number" step="0.001" />
</label>
</div>
</div>
</article>
<article class="card servers-card servers-card-modern">
<div class="server-card-head">
<h3 class="servers-title">Общий Фильтр Входа</h3>
<p class="muted">Применяется автоматически ко всем входным серверам.</p>
</div>
<div class="server-card-body">
<label class="field-control">
<span class="field-label">Фильтр включен</span>
<select id="shared-filter-enabled">
<option value="true">да</option>
<option value="false">нет</option>
</select>
</label>
<div class="field-grid field-grid-2">
<label class="field-control">
<span class="field-label">Мин. частота, МГц</span>
<input id="shared-min-freq" type="number" step="0.001" min="0" />
</label>
<label class="field-control">
<span class="field-label">Макс. частота, МГц</span>
<input id="shared-max-freq" type="number" step="0.001" min="0" />
</label>
</div>
<div class="field-grid field-grid-2">
<label class="field-control">
<span class="field-label">Мин. RSSI, дБм</span>
<input id="shared-min-rssi" type="number" step="0.1" />
</label>
<label class="field-control">
<span class="field-label">Макс. RSSI, дБм</span>
<input id="shared-max-rssi" type="number" step="0.1" />
</label>
</div>
</div>
</article>
<article class="card servers-card servers-card-modern">
<div class="server-card-head">
<h3 class="servers-title">Выходные Серверы</h3>
<p class="muted">Минимальные параметры для доставки результата.</p>
</div>
<div class="server-card-body">
<div class="selector-row">
<label class="field-control">
<span class="field-label">Активный выход</span>
<select id="output-select"></select>
</label>
<span id="output-count" class="badge badge-meta chip-counter">выходов: 0</span>
</div>
<div class="action-group">
<button id="add-output-server" class="btn" type="button">Добавить выход</button>
<button id="remove-output-server" class="btn" type="button">Удалить выход</button>
</div>
<div class="field-grid field-grid-2">
<label class="field-control">
<span class="field-label">Имя выхода</span>
<input id="out-name" type="text" placeholder="sink_main" />
</label>
<label class="field-control">
<span class="field-label">IP/хост выхода</span>
<input id="out-ip" type="text" placeholder="output-sink:8080" />
</label>
</div>
<label class="field-control">
<span class="field-label">Токен записи (API, только сессия)</span>
<input id="write-token" type="password" placeholder="необязательно" />
</label>
</div>
</article>
</div>
<article class="card servers-actions-card">
<div class="editor-actions">
<button id="load-servers" class="btn">Загрузить</button>
<button id="save-servers" class="btn btn-primary">Сохранить серверы</button>
<span id="servers-state" class="badge">серверы: н/д</span>
</div>
</article>
</section>
<section id="section-json" class="panel">
<article class="card config-head-card">
<h2>Конфигурация</h2>
<div class="editor-actions">
<button id="load-config" class="btn">Загрузить</button>
<button id="save-config" class="btn btn-primary">Сохранить конфиг</button>
<span id="config-state" class="badge">конфиг: н/д</span>
</div>
</article>
<div class="config-layout config-layout-modern">
<article class="card config-editor-card config-editor-modern">
<div class="config-section-head">
<h3>Редактор JSON</h3>
<p class="muted">Точный режим настройки для прод-конфигурации.</p>
</div>
<div class="config-editor-shell">
<div class="editor-toolbar">
<span class="editor-chip">JSON</span>
<span class="editor-chip">UTF-8</span>
<span class="editor-chip">runtime + input + system</span>
</div>
<textarea id="config-editor" class="editor" spellcheck="false"></textarea>
</div>
</article>
<article class="card config-help-card config-help-modern">
<div class="config-section-head">
<h3>Памятка По Полям</h3>
<p class="muted">Краткая структура и контрольные точки перед сохранением.</p>
</div>
<div class="config-hints config-hints-grid">
<p><b>input.receivers[]</b><br />входные ресиверы: координаты, URL, частоты.</p>
<p><b>runtime.output_servers[]</b><br />список серверов, получающих координаты.</p>
<p><b>input.default_input_filter</b><br />общий фильтр частот и RSSI.</p>
<p><b>system</b><br />системные таймеры, лимиты и автообновление.</p>
</div>
<h3>Советы</h3>
<ul class="config-tips">
<li>Поддерживайте уникальные `receiver_id` для каждого входа.</li>
<li>Согласуйте диапазоны частот между входными серверами.</li>
<li>Перед сохранением проверяйте JSON на валидность.</li>
</ul>
</article>
</div>
</section>
</section>
</main>
<script src="/static/app.js?v=20260312r5"></script>
<div id="toast-container" class="toast-container" aria-live="polite" aria-atomic="true"></div>
</body>
</html>