Files
Bridge-and-Join-s/internal/lkgateway/web/templates/admin_status.html
T

176 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{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"}}раз в час (и по кнопке «Проверить связь сейчас») запрос справочника участников 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>
<thead><tr><th></th><th>Подсистема</th><th>Состояние</th><th>Сообщение</th><th>Детали</th></tr></thead>
<tbody>
{{range .Checks}}
<tr>
<td><span class="dot {{if .OK}}ok{{else}}err{{end}}"></span></td>
<td><strong>{{.Name}}</strong></td>
<td>{{if .OK}}<span style="color: var(--ok)">OK</span>{{else}}<span style="color: var(--err)">FAIL</span>{{end}}</td>
<td>{{.Message}}</td>
<td><code>{{.Detail}}</code></td>
</tr>
{{end}}
</tbody>
</table>
<p class="muted" style="margin-top: 16px">Проверка выполнена в {{.CheckedAt.Format "15:04:05 02.01.2006"}}.</p>
</div>
{{/* Диагностика: службы, здоровье фоновых компонентов, справочник, тестовые прогоны (раньше — Настройка → Диагностика) */}}
<div class="card" id="sec-units"><a id="diag"></a>
<h2><span class="dot {{$bad := 0}}{{range .Units}}{{if not .OK}}{{$bad = 1}}{{end}}{{end}}{{if eq $bad 1}}err{{else}}ok{{end}}"></span>Службы</h2>
<p class="muted">Ядро и модули работают отдельными службами: если служба модуля не запущена, его раздел в bj отвечает ошибкой связи. Здесь видно состояние и можно перезапустить службу, не заходя на сервер.</p>
<div class="tw" style="margin-top:8px"><table>
<thead><tr>{{if devOn}}<th>Служба</th>{{end}}<th>Что делает</th><th>Состояние</th><th>С</th><th></th></tr></thead>
<tbody>{{range .Units}}<tr>
{{if devOn}}<td style="white-space:nowrap"><code>{{.Unit}}</code></td>{{end}}
<td>{{.Title}}</td>
<td>{{if .OK}}<span class="badge ok">работает</span>{{else}}<span class="badge err">не работает{{if devOn}}: {{.State}}{{with .Sub}} / {{.}}{{end}}{{with .Result}} ({{.}}){{end}}{{end}}</span>{{end}}</td>
<td class="muted">{{if .Since}}{{.Since}}{{else}}—{{end}}</td>
<td style="white-space:nowrap"><form method="post" action="/admin/setup/units/restart" style="margin:0" onsubmit="return confirm('{{if .Core}}Перезапустить bj? Страница настроек на несколько секунд станет недоступна.{{else}}Перезапустить «{{.Title}}»?{{end}}');">
<input type="hidden" name="section" value="sec-units"><input type="hidden" name="unit" value="{{.Unit}}">
<button type="submit" class="btn btn-secondary">Перезапустить</button></form></td>
</tr>{{end}}</tbody></table></div>
</div>
<div class="card">
<h2>Здоровье сервиса</h2>
<p class="muted">Фоновые компоненты под самоконтролем: при сбое перезапускаются автоматически, при зависании — перезапуск всего сервиса и запись в «Новости». Ниже — живой статус.</p>
{{if .Health}}
<div class="tw" style="margin-top:12px">
<table>
<thead><tr><th>Компонент</th><th>Состояние</th><th>Последняя отметка</th><th>Последняя ошибка</th></tr></thead>
<tbody>
{{range .Health}}
<tr>
<td>{{healthLabel .Name}}</td>
<td>{{if .Healthy}}<span class="sys-status" style="--dot:#16a34a">работает</span>{{else}}<span class="sys-status" style="--dot:#dc2626">не отвечает</span>{{end}}</td>
<td class="mono">{{dur .Age}} назад</td>
<td class="muted">{{if .LastErr}}{{.LastErr}}{{else}}—{{end}}</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{else}}
<p class="muted" style="margin-top:10px">Компоненты ещё не зарегистрированы (сервис только запущен).</p>
{{end}}
</div>
<div class="card">
<h2>Справочник участников M2M</h2>
<p class="muted">Справочник участников M2M из НРД: по нему bj узнаёт код участника по ИНН контрагента. bj запрашивает его сам; кнопка — запросить сейчас.</p>
<form method="post" action="/admin/setup/handbook-request" style="margin-top:12px"><button type="submit" class="btn">Запросить справочник у НРД</button></form>
<p class="muted" style="font-size:12px;margin-top:8px">Ответ НРД приходит через 30–60 секунд.</p>
</div>
{{if devOn}} <div class="card">
<h2>Тестовый пакет роботу НРД</h2>
<p class="muted">Робот <code>MC0012500000</code> эмулирует вторую сторону перевода. Выберите сценарий — bj-server отправит эталонный запрос через шлюз НРД, ответ придёт во входящие. Требуется настроенный шлюз НРД и ключ подписи.</p>
<form method="post" action="/admin/setup/test-nsd" style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center">
<select name="scenario">
<option value="2001">2001 — Принять все бумаги</option>
<option value="2002">2002 — Принять частично</option>
<option value="1111">1111 — Ответ с отказом</option>
<option value="3333">3333 — Робот принимающая сторона</option>
</select>
<button type="submit" class="btn">Отправить роботу</button>
</form>
<p class="muted" style="margin-top:6px;font-size:12px">Ответ робота — асинхронно (~30-60 сек) во входящие шлюза НРД.</p>
</div>
<div class="card">
<h2>Сквозной тестовый прогон (mock/реальный)</h2>
<p class="muted">Заявка с предзаполненными данными через всю цепочку до финального статуса.</p>
<form method="post" action="/admin/setup/test-run" style="margin-top:12px"><button type="submit" class="btn">Запустить тестовую заявку</button></form>
{{if .LastTest}}
<div style="margin-top:16px;padding:14px;background:var(--card-2);border:1px solid var(--border);border-radius:10px">
<strong>Последний прогон</strong>
<table style="margin-top:8px">
<tbody>
<tr><td style="width:160px" class="muted">Статус</td><td>{{if .LastTest.OK}}<span style="color:var(--ok)">✓ успешно</span>{{else}}<span style="color:var(--err)">✗ не прошёл</span>{{end}}</td></tr>
<tr><td class="muted">FSM-статус</td><td><code>{{.LastTest.FinalStatus}}</code></td></tr>
<tr><td class="muted">ClaimID</td><td><code>{{.LastTest.ClaimID}}</code> {{if .LastTest.ClaimID}}<a href="/admin/claims/{{.LastTest.ClaimID}}">→ карточка</a>{{end}}</td></tr>
<tr><td class="muted">Сообщение</td><td>{{.LastTest.Message}}</td></tr>
</tbody>
</table>
</div>
{{end}}
</div>{{end}}
<div class="card">
<h2>DEPO: что нужно bj</h2>
<p class="muted">Снимок объектов bj в базе DEPO: трансферные таблицы и процедуры FTV_M2M* (даты изменения), зависимости поставки Fancy, права логина bj, счётчики по статусам. Данных клиентов в снимке нет. bj снимает его раз в сутки и хранит историю — по ней видно, что и когда меняли в DEPO.</p>
<a class="btn" href="/admin/status/depo-snapshot" target="_blank" rel="noopener">Снять снимок сейчас (JSON)</a>
</div>
{{if devOn}}{{/* дорожная карта разработки — только в режиме разработки */}}
<div class="card">
<h2>Что подключается на следующих этапах</h2>
<table>
<tr><td class="muted" style="width:240px">PostgreSQL (схема m2m_core)</td><td>M2-шаг-3: pgx-репозиторий вместо MemoryRepository. Миграция готова — <code>migrations/m2m-core/001__deals.sql</code>.</td></tr>
<tr><td class="muted">crypto-service · Валидата PKCS#11</td><td>M4: установить АПК «Валидата Клиент L» (<code>zpki</code>, <code>zsdk</code>), выставить <code>BJ_CRYPTO_PROVIDER=validata</code> и путь к <code>libvdpkcs11.so</code>. Проверка — Health PKCS#11 должна вернуть <code>provider=validata, ok=true</code>.</td></tr>
<tr><td class="muted">nsd-adapter · ИШ НРД</td><td>M3: установить ИШ, выставить <code>BJ_NSD_PROFILE=guest-gost</code> или иной, <code>BJ_NSD_IGW_URL=http://localhost:8080</code>. Без этого сейчас используется <code>nsdadapter/mock</code> с эмуляцией ответов через 3 сек.</td></tr>
<tr><td class="muted">Реальный ЛК (ESIA Finance)</td><td>M4: согласовать <code>docs/lk-contract/v1/openapi.yaml</code> с командой ЛК, выставить <code>BJ_LK_CALLBACK_URL</code> на реальный адрес. Сейчас callback идёт в встроенный lk-emulator.</td></tr>
</table>
</div>
{{end}}
{{end}}