Мониторинг связи с НРД: участки Шлюз/НРД/M2M/Отправка, сквозная проверка справочником раз в 10 мин, история за сутки на «Статусе», цепочка в шапке (30 с), автоповтор недоставленных до 24 ч, баннер и статус «ожидает отправки» в кабинете клиента

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:17:25 +03:00
parent a0f6ce9f7b
commit 4cbefa41d5
18 changed files with 1075 additions and 62 deletions
@@ -1,4 +1,58 @@
{{define "content"}}
{{if .NSDLink.Configured}}<div class="card" id="nsd">
<h2 style="display:flex;align-items:center;gap:10px;flex-wrap:wrap">Связь с НРД
<span class="badge {{if eq .NSDLink.State "ok"}}confirmed{{else if eq .NSDLink.State "err"}}rejected{{else}}awaiting_decision{{end}}">{{if eq .NSDLink.State "ok"}}работает{{else if eq .NSDLink.State "err"}}сбой{{else if eq .NSDLink.State "warn"}}с перебоями{{else}}нет данных{{end}}</span>
{{if can "operate"}}<form method="post" action="/admin/status/nsd-probe" style="margin:0 0 0 auto"><button class="btn" type="submit">Проверить связь сейчас</button></form>{{end}}
</h2>
{{if .Probe}}<p class="muted">Запрос проверки отправлен — ответ НРД обычно приходит за 20–60 с. Страница обновится сама.</p>{{end}}
<p class="muted" style="margin-top:0">Зелёный — только при свежем подтверждении от НРД, а не при отсутствии ошибок. {{if .NSDLink.Ago}}Последний ответ НРД — {{.NSDLink.Ago}}.{{end}}</p>
<table>
<thead><tr><th></th><th>Участок</th><th>Состояние</th><th>Чем проверяем</th></tr></thead>
<tbody>
{{range .NSDLink.Segs}}<tr>
<td><span class="nsd-dot {{.State}}"></span></td>
<td><strong>{{.Title}}</strong></td>
<td>{{.Text}}{{with .Detail}}<br><code>{{.}}</code>{{end}}</td>
<td class="muted" style="font-size:12.5px">{{if eq .Key "igw"}}bj обращается к шлюзу каждые 30 с{{else if eq .Key "nsd"}}журнал шлюза: ответы НРД на опросы входящих{{else if eq .Key "m2m"}}раз в 10 мин запрос справочника участников M2M и ответ на него — весь путь до сервиса M2M и обратно{{else}}подтверждение доставки каждого отправленного пакета{{end}}</td>
</tr>{{end}}
</tbody>
</table>
<h3 style="margin:18px 0 6px;font-size:14px">За последние сутки <span class="muted" style="font-weight:400;font-size:12px">с {{.StripFrom}}, отрезок — 10 минут</span></h3>
<div class="nsd-strip">
{{range .Strip}}<div class="nsd-row"><span class="nsd-t">{{.Title}}</span><span class="nsd-cells">{{range .Cells}}<i class="{{.State}}" title="{{.Title}}"></i>{{end}}</span><span class="nsd-b muted">{{.Bad}}</span></div>{{end}}
<div class="nsd-legend muted"><i class="ok"></i>работает <i class="warn"></i>перебои <i class="err"></i>сбой <i class="none"></i>нет данных</div>
</div>
{{if .Fails}}<h3 style="margin:18px 0 6px;font-size:14px">Не доставлены в НРД</h3>
<table>
<thead><tr><th>Перевод</th><th>Причина</th><th>Первая попытка</th><th>Попыток</th><th></th></tr></thead>
<tbody>{{range .Fails}}<tr>
<td><a href="/admin/claims/{{.DealID}}"><code>{{slice .GUID 0 8}}</code></a></td>
<td>{{.Text}}</td>
<td>{{.FirstAt.Format "02.01 15:04"}}</td>
<td>{{.Attempts}}</td>
<td>{{if .GaveUp}}<span style="color:var(--err)">автоповтор остановлен (прошли сутки)</span>{{else}}<span class="muted">отправится сам, когда НРД ответит</span>{{end}}{{if can "operate"}}<form method="post" action="/admin/claims/{{.DealID}}/resend" style="margin:4px 0 0"><button class="btn" type="submit" style="padding:2px 10px;font-size:12px">Отправить сейчас</button></form>{{end}}</td>
</tr>{{end}}</tbody>
</table>{{end}}
</div>
<style>
.nsd-dot { width:10px; height:10px; border-radius:50%; display:inline-block; background:var(--muted); }
.nsd-dot.ok { background:var(--ok); } .nsd-dot.warn { background:var(--warn); } .nsd-dot.err { background:var(--err); }
.nsd-strip { display:flex; flex-direction:column; gap:6px; }
.nsd-row { display:grid; grid-template-columns:80px 1fr 130px; align-items:center; gap:10px; }
.nsd-t { font-size:13px; font-weight:600; }
.nsd-b { font-size:12px; text-align:right; }
.nsd-cells { display:grid; grid-template-columns:repeat(144, 1fr); gap:1px; height:18px; }
.nsd-cells i, .nsd-legend i { display:block; border-radius:2px; background:var(--border); }
.nsd-cells i.ok, .nsd-legend i.ok { background:var(--ok); } .nsd-cells i.warn, .nsd-legend i.warn { background:var(--warn); }
.nsd-cells i.err, .nsd-legend i.err { background:var(--err); } .nsd-cells i.unknown { background:var(--muted); opacity:.35; }
.nsd-legend { display:flex; align-items:center; gap:6px; font-size:12px; margin-top:4px; }
.nsd-legend i { width:10px; height:10px; display:inline-block; margin-left:8px; }
@media (max-width:700px){ .nsd-row { grid-template-columns:1fr; } .nsd-b { text-align:left; } }
</style>
<script>setTimeout(function(){ if (!document.querySelector('main form input:focus')) location.reload(); }, {{if .Probe}}20000{{else}}60000{{end}});</script>
{{end}}
<div class="card">
<h2>Статус системы — детально</h2>
<table>