a519b78eb2
The camera table actions column (log/restart/delete buttons) is removed: the table drops to 8 columns across thead, filled rows, empty slots and the bulk-edit rows. The now-orphaned log subrow and openLogs tracking are gone. Camera rows get a hard fixed height of 22px via a new table.cams.cams-fixed rule (zero vertical padding, 22px line-height) so rows never inflate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
289 lines
16 KiB
HTML
289 lines
16 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>CoRE.Vision — Настройки</title>
|
||
<link rel="stylesheet" href="/static/style.css">
|
||
</head>
|
||
<body data-page="settings">
|
||
<div class="layout">
|
||
<aside>
|
||
<a class="nav-item" href="/" data-nav="live"><span class="ico">▦</span>Live view</a>
|
||
<div class="subnav">
|
||
<a class="subitem" data-grid="2" href="/?grid=2">4</a>
|
||
<a class="subitem" data-grid="3" href="/?grid=3">9</a>
|
||
<a class="subitem" data-grid="4" href="/?grid=4">16</a>
|
||
<a class="subitem" data-grid="5" href="/?grid=5">25</a>
|
||
<a class="subitem" data-grid="6" href="/?grid=6">36</a>
|
||
<a class="subitem" data-grid="7" href="/?grid=7">49</a>
|
||
<a class="subitem" data-grid="8" href="/?grid=8">64</a>
|
||
</div>
|
||
<a class="nav-item" href="/archive" data-nav="archive"><span class="ico">🗄</span>Архив</a>
|
||
<div class="aside-spacer"></div>
|
||
<a class="nav-item active" href="/settings" data-nav="settings"><span class="ico">⚙</span>Настройки</a>
|
||
</aside>
|
||
|
||
<main class="settings-main">
|
||
<div class="tabs">
|
||
<button class="tab active" data-tab="cams" data-min-role="admin">Камеры</button>
|
||
<button class="tab" data-tab="storage" data-min-role="admin">Хранилища</button>
|
||
<button class="tab" data-tab="layout">Раскладка</button>
|
||
<button class="tab" data-tab="player" data-min-role="operator">Плеер</button>
|
||
<button class="tab" data-tab="users" data-min-role="superadmin">Пользователи</button>
|
||
<button class="tab" data-tab="general" data-min-role="operator">Система</button>
|
||
<button class="tab" data-tab="optim" data-min-role="superadmin">Доп настройки</button>
|
||
</div>
|
||
|
||
<!-- ВКЛАДКА 1: Камеры -->
|
||
<div class="tab-panel" data-panel="cams" data-min-role="admin">
|
||
<div class="card">
|
||
<div class="card-head">
|
||
<h2>Камеры — 64 слота</h2>
|
||
<div style="display:flex;gap:8px">
|
||
<button id="bulk-edit">Изменить</button>
|
||
<button id="bulk-cancel" hidden>Отмена</button>
|
||
</div>
|
||
</div>
|
||
<table class="cams cams-fixed">
|
||
<thead>
|
||
<tr><th style="width:48px">ID</th><th>Камера</th><th>IP</th><th>Потоки</th><th style="width:56px">Вкл</th><th style="width:64px">Запись</th><th style="width:150px">Хранилище</th><th data-bulk-label="Логин / пароль">Статус</th></tr>
|
||
</thead>
|
||
<tbody id="cam-rows"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ВКЛАДКА: Хранилища (управление записью) -->
|
||
<div class="tab-panel" data-panel="storage" data-min-role="admin" hidden>
|
||
<div class="card">
|
||
<div class="card-head">
|
||
<h2>Хранилища записи</h2>
|
||
<button id="stor-add">+ Добавить хранилище</button>
|
||
</div>
|
||
<div class="muted" style="margin-bottom:12px">
|
||
Активное хранилище — куда пишутся новые записи. Квота задаётся на каждое хранилище
|
||
(0 = без лимита) и правится прямо в таблице. После смены активного старые записи
|
||
остаются доступны в Архиве. Удаление хранилища убирает его из списка — файлы записей
|
||
НЕ удаляются.
|
||
</div>
|
||
<table class="cams">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:74px">Активно</th>
|
||
<th style="width:90px">ID</th>
|
||
<th>Название</th>
|
||
<th style="width:56px">Тип</th>
|
||
<th>Путь</th>
|
||
<th style="width:130px">Квота, ГБ</th>
|
||
<th style="width:150px">Занято / диск</th>
|
||
<th style="width:130px">Статус</th>
|
||
<th style="width:48px"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="stor-rows"></tbody>
|
||
</table>
|
||
<div class="muted" id="stor-msg" style="margin-top:10px;font-size:12px"></div>
|
||
</div>
|
||
|
||
<!-- форма добавления (скрыта по умолчанию) -->
|
||
<div class="card" id="stor-form-card" hidden>
|
||
<h2>Новое хранилище</h2>
|
||
<div class="cam-edit-grid">
|
||
<label>ID<input type="text" id="sf-id" placeholder="arch2"></label>
|
||
<label>Название<input type="text" id="sf-name" placeholder="Архив 2"></label>
|
||
<label>Тип
|
||
<select id="sf-type">
|
||
<option value="local">Локальное (папка)</option>
|
||
<option value="nas">NAS (SMB)</option>
|
||
</select>
|
||
</label>
|
||
<label>Квота, ГБ (0 = без лимита)<input type="number" id="sf-quota" min="0" value="0"></label>
|
||
<label class="sf-local">Папка<input type="text" id="sf-path" placeholder="/storages/arch2 (по умолчанию)"></label>
|
||
<label class="sf-nas" hidden>SMB сервер (IP)<input type="text" id="sf-server" placeholder="192.168.1.10"></label>
|
||
<label class="sf-nas" hidden>Шара (share)<input type="text" id="sf-share" placeholder="cctv"></label>
|
||
<label class="sf-nas" hidden>Логин<input type="text" id="sf-user"></label>
|
||
<label class="sf-nas" hidden>Пароль<input type="password" id="sf-pass"></label>
|
||
<label class="sf-nas" hidden>Подпапка (необяз.)<input type="text" id="sf-subpath" placeholder="cam-archive"></label>
|
||
</div>
|
||
<div class="cam-edit-foot">
|
||
<span class="err" id="sf-err"></span>
|
||
<button id="sf-save" class="primary">Создать</button>
|
||
<button id="sf-cancel">Отмена</button>
|
||
</div>
|
||
<div class="muted" id="sf-mount" style="margin-top:10px;font-size:12px;white-space:pre-wrap"></div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>Политика записи <span class="muted" style="font-weight:400;font-size:12px">— общая для всех хранилищ</span></h2>
|
||
<div class="cam-edit-grid">
|
||
<label>Длина сегмента
|
||
<select id="pol-segment">
|
||
<option value="60">1 минута</option>
|
||
<option value="120">2 минуты</option>
|
||
<option value="300">5 минут</option>
|
||
<option value="600">10 минут</option>
|
||
<option value="900">15 минут</option>
|
||
</select>
|
||
</label>
|
||
<label>Срок хранения, дней (0 = не удалять по возрасту)<input type="number" id="pol-retention" min="0" max="3650"></label>
|
||
</div>
|
||
<div style="margin-top:12px"><button id="pol-save">Сохранить</button></div>
|
||
<div class="muted" id="pol-saved" style="margin-top:8px;font-size:12px"></div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>Активное хранилище <span class="muted" style="font-weight:400;font-size:12px">— сводка</span></h2>
|
||
<div class="kv" id="storage-kv"><div class="muted">загрузка…</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ВКЛАДКА 2: Система -->
|
||
<div class="tab-panel" data-panel="general" data-min-role="operator" hidden>
|
||
<div class="wrap">
|
||
<div class="card">
|
||
<h2>Система</h2>
|
||
<div class="kv" id="system-kv"><div class="muted">загрузка…</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ВКЛАДКА: Плеер и перекодирование (этот браузер) -->
|
||
<div class="tab-panel" data-panel="player" data-min-role="operator" hidden>
|
||
<div class="wrap">
|
||
<div class="card">
|
||
<h2>Плеер и перекодирование <span class="muted" style="font-weight:400;font-size:12px">— настройки этого браузера</span></h2>
|
||
<div class="muted" style="margin-top:-4px;margin-bottom:16px;font-size:12px">
|
||
Для каждого потока выберите способ воспроизведения: <b>как есть</b> —
|
||
поток отдаётся без обработки (ffmpeg -c copy), браузер декодирует HEVC сам
|
||
(нужна аппаратная поддержка); <b>встроенный плеер</b> — декодирует H.265
|
||
в браузере софтом (WASM hevc.js, в Web Worker), тянет и основной поток
|
||
(3200×1800, включая тайлы), и субпоток, без нагрузки на сервер (декод
|
||
нагружает CPU клиента); <b>WebCodecs (железо)</b> — аппаратный декод H.265 на GPU клиента,
|
||
тянет основной поток 3200×1800 при 0% CPU сервера (рекомендуется для
|
||
основного потока); <b>перекодировать</b> — сервер транскодирует в H.264 /
|
||
VP9 (нагрузка на CPU сервера, для слабых клиентов).
|
||
</div>
|
||
<!-- 3 независимых профиля: 1 поток / 2 поток / архив -->
|
||
<div class="tr-block" data-tr="1">
|
||
<h3>1 поток (основной)</h3>
|
||
<div class="seg-toggle">
|
||
<label><input type="radio" name="mode-1" value="native"><span>Как есть</span></label>
|
||
<label><input type="radio" name="mode-1" value="player"><span>Встроенный плеер</span></label>
|
||
<label><input type="radio" name="mode-1" value="webcodecs"><span>WebCodecs (железо)</span></label>
|
||
<label><input type="radio" name="mode-1" value="transcode"><span>Перекодировать</span></label>
|
||
</div>
|
||
<div class="tr-row"></div>
|
||
</div>
|
||
|
||
<div class="tr-block" data-tr="2">
|
||
<h3>2 поток (суб)</h3>
|
||
<div class="seg-toggle">
|
||
<label><input type="radio" name="mode-2" value="native"><span>Как есть</span></label>
|
||
<label><input type="radio" name="mode-2" value="player"><span>Встроенный плеер</span></label>
|
||
<label><input type="radio" name="mode-2" value="webcodecs"><span>WebCodecs (железо)</span></label>
|
||
<label><input type="radio" name="mode-2" value="transcode"><span>Перекодировать</span></label>
|
||
</div>
|
||
<div class="tr-row"></div>
|
||
</div>
|
||
|
||
<div class="tr-block" data-tr="a">
|
||
<h3>Архив</h3>
|
||
<div class="seg-toggle">
|
||
<label><input type="radio" name="mode-a" value="native"><span>Как есть</span></label>
|
||
<label><input type="radio" name="mode-a" value="player"><span>Встроенный плеер</span></label>
|
||
<label><input type="radio" name="mode-a" value="transcode"><span>Перекодировать</span></label>
|
||
</div>
|
||
<div class="tr-row"></div>
|
||
</div>
|
||
|
||
<div style="margin-top:16px"><button id="prefs-save">Сохранить</button></div>
|
||
<div class="muted" id="prefs-saved" style="margin-top:8px;font-size:12px">Сохраняется в этом браузере</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ВКЛАДКА: Раскладка (назначение камер по ячейкам, этот браузер) -->
|
||
<div class="tab-panel" data-panel="layout" hidden>
|
||
<div class="card">
|
||
<div class="card-head">
|
||
<h2>Настройка раскладки</h2>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<label class="muted">Раскладка:</label>
|
||
<select id="layout-dim">
|
||
<option value="2">4 (2×2)</option>
|
||
<option value="3">9 (3×3)</option>
|
||
<option value="4">16 (4×4)</option>
|
||
<option value="5">25 (5×5)</option>
|
||
<option value="6">36 (6×6)</option>
|
||
<option value="7">49 (7×7)</option>
|
||
<option value="8">64 (8×8)</option>
|
||
</select>
|
||
<button id="layout-save">Сохранить</button>
|
||
</div>
|
||
</div>
|
||
<div class="muted" style="margin-bottom:12px">Назначьте камеру в каждую ячейку раскладки. Сохраняется в этом браузере.</div>
|
||
<div id="layout-grid" class="layout-grid"></div>
|
||
<div class="muted" id="layout-saved" style="margin-top:12px;font-size:12px"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ВКЛАДКА: Доп настройки (только суперадмин) -->
|
||
<div class="tab-panel" data-panel="optim" data-min-role="superadmin" hidden>
|
||
<div class="wrap">
|
||
<div class="card">
|
||
<h2>Live view <span class="muted" style="font-weight:400;font-size:12px">— общая политика для всех клиентов</span></h2>
|
||
<label class="toggle" style="color:var(--text)">
|
||
<input type="checkbox" id="single-main">
|
||
Не более одного основного потока в режиме Live view
|
||
</label>
|
||
<div class="muted" style="margin-top:8px;font-size:12px">
|
||
Включено по умолчанию. Основной (HD) поток можно держать одновременно
|
||
только в одной ячейке — при переключении другой ячейки на «1»
|
||
предыдущая вернётся на субпоток. Снижает нагрузку на сеть и камеры.
|
||
</div>
|
||
<label class="toggle" style="color:var(--text);margin-top:18px">
|
||
<input type="checkbox" id="mode-16plus">
|
||
Режим 16+
|
||
</label>
|
||
<div class="muted" style="margin-top:8px;font-size:12px">
|
||
По умолчанию в Live view доступно не более 16 камер (сетки до 4×4).
|
||
Включите «16+», чтобы открыть раскладки 25 / 36 / 49 / 64.
|
||
</div>
|
||
<div class="muted" style="margin-top:12px;font-size:12px">
|
||
<b>Менять может только суперадмин с подтверждением пароля.</b>
|
||
</div>
|
||
<div style="margin-top:14px"><button id="optim-save">Сохранить</button></div>
|
||
<div class="muted" id="optim-saved" style="margin-top:8px;font-size:12px">Смена требует пароль</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ВКЛАДКА 4: Пользователи (только суперадмин) -->
|
||
<div class="tab-panel" data-panel="users" data-min-role="superadmin" hidden>
|
||
<div class="card">
|
||
<h2>Учётная запись</h2>
|
||
<div class="muted" id="me-info" style="margin-bottom:10px;font-size:13px"></div>
|
||
<button id="logout">Выйти из системы</button>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-head">
|
||
<h2>Пользователи и роли</h2>
|
||
<button id="add-user">+ Добавить пользователя</button>
|
||
</div>
|
||
<table class="cams">
|
||
<thead>
|
||
<tr><th>Логин</th><th style="width:160px">Роль</th><th style="width:220px">Пароль</th><th style="width:120px"></th></tr>
|
||
</thead>
|
||
<tbody id="user-rows"></tbody>
|
||
</table>
|
||
<div class="muted" id="users-msg" style="margin-top:10px;font-size:12px"></div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
<script src="/static/app.js"></script>
|
||
</body>
|
||
</html>
|