Шапка: одна плашка «Шлюз НРД», подробности по участкам — в подсказке

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
zuevav
2026-09-25 16:21:43 +03:00
parent 4cbefa41d5
commit d4237c9da3
3 changed files with 17 additions and 22 deletions
+4 -4
View File
@@ -8,8 +8,8 @@
"version": "2026.09.25.24" "version": "2026.09.25.24"
}, },
"bj-lk": { "bj-lk": {
"fingerprint": "f69c9f1193814138752f1bfce6044b4cad94957c1ac64e7c0920993b91cf0f70", "fingerprint": "37bf4ba7d13bc3cfb52032dfb95851b9d5d702f1a2244e185a1b6a5b87a5cfc6",
"version": "2026.09.25.14" "version": "2026.09.25.31"
}, },
"bj-npr": { "bj-npr": {
"fingerprint": "5b5301b0c18bfd001bdff3f3b35a9ff6ccccb4f24eb4b88b0334d34d1b63df81", "fingerprint": "5b5301b0c18bfd001bdff3f3b35a9ff6ccccb4f24eb4b88b0334d34d1b63df81",
@@ -20,8 +20,8 @@
"version": "2026.09.25.14" "version": "2026.09.25.14"
}, },
"bj-server": { "bj-server": {
"fingerprint": "36f004afd74a7f8006de52aa513ca98e60d5a94397699f4fe65fc65dbadb0a3e", "fingerprint": "6ee366a451428635fe57ac84174673cf3ae4a9645cd0ef4b4cd6b7059673508a",
"version": "2026.09.25.29" "version": "2026.09.25.31"
}, },
"crypto-service.jar": { "crypto-service.jar": {
"fingerprint": "2c4fd536bc9b1c20c69a70e8dcd374a61847b263aeb2e474c45debb01fbd8233", "fingerprint": "2c4fd536bc9b1c20c69a70e8dcd374a61847b263aeb2e474c45debb01fbd8233",
+5
View File
@@ -563,6 +563,11 @@ func nsdSegTip(h NSDHealth) string {
} }
b.WriteString("\n") b.WriteString("\n")
} }
if h.Ago != "" {
b.WriteString("Последний ответ НРД " + h.Ago + "\n")
} else {
b.WriteString("Ответа НРД ещё не было\n")
}
b.WriteString("Подробно — «Статус». Обновляется каждые 30 с.") b.WriteString("Подробно — «Статус». Обновляется каждые 30 с.")
return b.String() return b.String()
} }
+8 -18
View File
@@ -100,15 +100,11 @@ body {
.theme-toggle svg { width:16px; height:16px; } .theme-toggle svg { width:16px; height:16px; }
.theme-toggle:hover { background:var(--border); color:var(--text); } .theme-toggle:hover { background:var(--border); color:var(--text); }
.topbar .clock { font-size:11px; color:var(--muted); font-family:var(--mono); font-variant-numeric:tabular-nums; letter-spacing:-0.02em; } .topbar .clock { font-size:11px; color:var(--muted); font-family:var(--mono); font-variant-numeric:tabular-nums; letter-spacing:-0.02em; }
.nsd-chain { text-decoration:none; gap:6px; } .nsd-chain { text-decoration:none; }
.nsd-chain .seg { display:inline-flex; align-items:center; gap:4px; } .nsd-chain i { width:8px; height:8px; border-radius:50%; background:var(--muted); display:inline-block; }
.nsd-chain .seg i { width:8px; height:8px; border-radius:50%; background:var(--muted); display:inline-block; } .nsd-chain.ok i { background:var(--ok); } .nsd-chain.warn i { background:var(--warn); } .nsd-chain.err i { background:var(--err); }
.nsd-chain .seg.ok i { background:var(--ok); } .nsd-chain .seg.warn i { background:var(--warn); } .nsd-chain .seg.err i { background:var(--err); } .nsd-chain.err { background:var(--err-weak); border-color:var(--err); color:var(--err); }
.nsd-chain .seg.err { color:var(--err); } .nsd-chain .sep { color:var(--muted); font-weight:400; }
.nsd-chain .ago { font-weight:400; color:var(--muted); }
.nsd-chain.err { background:var(--err-weak); border-color:var(--err); }
.nsd-chain.warn { background:var(--warn-weak); } .nsd-chain.warn { background:var(--warn-weak); }
@media (max-width:1100px){ .nsd-chain .seg > span, .nsd-chain .ago, .nsd-chain .sep { display:none } }
.sys-block { display:inline-flex; flex-direction:column; align-items:center; gap:2px; line-height:1.1; } .sys-block { display:inline-flex; flex-direction:column; align-items:center; gap:2px; line-height:1.1; }
.sys-block .sys-status { padding:3px 9px 3px 7px; font-size:11.5px; } .sys-block .sys-status { padding:3px 9px 3px 7px; font-size:11.5px; }
.user-dd .ddbtn.user-chip { display:inline-flex; flex-direction:column; align-items:flex-start; padding:4px 10px; border-radius:8px; margin:0; max-width:220px; } .user-dd .ddbtn.user-chip { display:inline-flex; flex-direction:column; align-items:flex-start; padding:4px 10px; border-radius:8px; margin:0; max-width:220px; }
@@ -358,7 +354,7 @@ label { font-size:13px; font-weight:500; }
</nav> </nav>
<div class="topbar-right"> <div class="topbar-right">
<span class="sys-block"> <span class="sys-block">
{{if and .NSDLink.Configured (not .IsMockMode)}}<a id="nsd-chain" href="/admin/status#nsd" class="sys-status nsd-chain {{.NSDLink.State}}" title="{{nsdSegTip .NSDLink}}">{{range $i, $s := .NSDLink.Segs}}{{if $i}}<span class="sep" aria-hidden="true">›</span>{{end}}<span class="seg {{$s.State}}"><i></i><span>{{$s.Title}}</span></span>{{end}}<span class="ago">{{if .NSDLink.Ago}}ответ НРД {{.NSDLink.Ago}}{{else}}ответа НРД ещё не было{{end}}</span></a>{{else}}<span class="sys-status {{if .IsMockMode}}warn{{end}}" title="Состояние обмена с НРД"> {{if and .NSDLink.Configured (not .IsMockMode)}}<a id="nsd-chain" href="/admin/status#nsd" class="sys-status nsd-chain {{.NSDLink.State}}" title="{{nsdSegTip .NSDLink}}"><i></i><span>Шлюз НРД</span></a>{{else}}<span class="sys-status {{if .IsMockMode}}warn{{end}}" title="Состояние обмена с НРД">
<span class="pulse"></span>{{if .IsMockMode}}{{if devOn}}Эмуляция{{else}}Нет связи с НРД{{end}}{{else}}НРД на связи{{end}}</span>{{end}} <span class="pulse"></span>{{if .IsMockMode}}{{if devOn}}Эмуляция{{else}}Нет связи с НРД{{end}}{{else}}НРД на связи{{end}}</span>{{end}}
<span class="clock">{{.Now}}</span> <span class="clock">{{.Now}}</span>
</span> </span>
@@ -566,18 +562,12 @@ label { font-size:13px; font-weight:500; }
(function(){ (function(){
var el = document.getElementById('nsd-chain'); var el = document.getElementById('nsd-chain');
if (!el) return; if (!el) return;
function esc(t){ return String(t).replace(/[&<>"]/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]; }); }
function upd(){ function upd(){
fetch('/admin/nsd-health.json', {cache:'no-store'}).then(function(r){ return r.json(); }).then(function(h){ fetch('/admin/nsd-health.json', {cache:'no-store'}).then(function(r){ return r.json(); }).then(function(h){
if (!h.configured) return; if (!h.configured) return;
var html = '', tip = ''; var tip = '';
(h.segs||[]).forEach(function(s, i){ (h.segs||[]).forEach(function(s){ tip += s.title + ': ' + s.text + (s.detail ? ' (' + s.detail + ')' : '') + '\n'; });
if (i) html += '<span class="sep" aria-hidden="true">›</span>'; tip += (h.ago ? 'Последний ответ НРД ' + h.ago : 'Ответа НРД ещё не было') + '\n';
html += '<span class="seg ' + esc(s.state) + '"><i></i><span>' + esc(s.title) + '</span></span>';
tip += s.title + ': ' + s.text + (s.detail ? ' (' + s.detail + ')' : '') + '\n';
});
html += '<span class="ago">' + (h.ago ? 'ответ НРД ' + esc(h.ago) : 'ответа НРД ещё не было') + '</span>';
el.innerHTML = html;
el.className = 'sys-status nsd-chain ' + h.state; el.className = 'sys-status nsd-chain ' + h.state;
el.title = tip + 'Подробно — «Статус». Обновляется каждые 30 с.'; el.title = tip + 'Подробно — «Статус». Обновляется каждые 30 с.';
}).catch(function(){ }).catch(function(){