diff --git a/VERSION b/VERSION index 1ad6b81..9ab8fdd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.131 +0.0.132 diff --git a/frontend/static/app.js b/frontend/static/app.js index ae55709..d7a9bf1 100644 --- a/frontend/static/app.js +++ b/frontend/static/app.js @@ -106,6 +106,21 @@ function fmtUptime(s) { const STATE_RU = { online: "запись", retrying: "переподключение", offline: "выключена", starting: "запуск" }; function dotClass(state) { return "dot " + (state || "offline"); } +// Канал Hikvision (1-32) ↔ пути RTSP: канал N → осн. /Streaming/Channels/{N*100+1}, +// суб /Streaming/Channels/{N*100+2} (101/102 = канал 1, 1101/1102 = канал 11, 3201/3202 = 32). +function channelFromPath(p) { + const m = /(\d+)\s*$/.exec(p || ""); + const ch = m ? Math.floor(parseInt(m[1], 10) / 100) : 1; + return ch >= 1 ? ch : 1; +} +function mainPathForChannel(ch) { return `/Streaming/Channels/${ch * 100 + 1}`; } +function subPathForChannel(ch) { return `/Streaming/Channels/${ch * 100 + 2}`; } +function channelOptions(sel) { + let h = ""; + for (let i = 1; i <= 32; i++) h += ``; + return h; +} + // ── шапка: часы + статистика + выход ──────────────────────────── function startClock() { const el = document.getElementById("clock"); @@ -1204,10 +1219,7 @@ const CamSettings = { `${slotNo}` + `` + `` + - `` + - `` + - `` + - `` + + `` + `` + `` + `` + @@ -1239,8 +1251,8 @@ const CamSettings = { ip: get("ip").trim(), user: get("user").trim(), password: get("password"), - main_path: get("main_path").trim(), - sub_path: get("sub_path").trim(), + main_path: mainPathForChannel(+get("channel") || 1), + sub_path: subPathForChannel(+get("channel") || 1), storage_id: get("storage_id"), enabled: tr.querySelector('[data-f="enabled"]').checked, record: tr.querySelector('[data-f="record"]').checked, @@ -1281,8 +1293,7 @@ const CamSettings = { `` + `` + `` + - `` + - `` + + `` + `` + `` + `` + @@ -1325,8 +1336,8 @@ const CamSettings = { ip: val("e-ip").trim(), user: val("e-user").trim(), password: val("e-pass"), - main_path: val("e-main").trim(), - sub_path: val("e-sub").trim(), + main_path: mainPathForChannel(+val("e-channel") || 1), + sub_path: subPathForChannel(+val("e-channel") || 1), storage_id: val("e-storage"), enabled: document.getElementById("e-enabled").checked, record: document.getElementById("e-record").checked, @@ -1380,7 +1391,7 @@ const CamSettings = { const tr = document.createElement("tr"); if (c) { const st = (c.status && c.status.state) || "offline"; - const streams = "осн. 101" + (c.has_sub ? " + суб. 102" : ""); + const streams = "канал " + channelFromPath(c.main_path); const statusCell = c.enabled ? `${STATE_RU[st] || st}` : `выключена`; diff --git a/frontend/static/style.css b/frontend/static/style.css index 28730ec..26a8d43 100644 --- a/frontend/static/style.css +++ b/frontend/static/style.css @@ -437,8 +437,8 @@ button.primary { background: var(--accent); border-color: #c0392b; color: #fff; button.danger { border-color: #c0392b; color: #e74c3c; } button.danger:hover { background: #c0392b; border-color: #c0392b; color: #fff; } table.cams td.actions button { padding: 2px 8px; font-size: 12px; } -/* инлайн-выбор хранилища в строке — компактный, не раздувает высоту строки (как тумблеры) */ -table.cams td select.stor-sel { +/* инлайн-селекты в строке (хранилище, канал) — компактные, не раздувают высоту строки */ +table.cams td select.stor-sel, table.cams td select.cell-sel { height: 22px; padding: 1px 4px; font-size: 12px; line-height: 1; border-radius: 5px; width: 100%; max-width: 150px; box-sizing: border-box; vertical-align: middle;