ffd69b0698
На 9 при одном входящем переводе (Витвицкий) дашборд показывал «Переводов ещё нет»: сводка и «Последние переводы» считали только исходящие, и только последние 200. - Сводка по направлениям: исходящие и входящие — всего, исполнено, в работе, отказ / истёк срок; исход — по состоянию «чего ждёт заявка» (livestatus.go), то же, что в журнале: принятый, но не исполненный перевод — «в работе». - Период «Сегодня / Всего» (?period=, выбор помнится в куке; по умолчанию — сегодня, с 00:00 МСК). Плитка «Переводы» ведёт в журнал, счётчики за всё время. - «Последние переводы» — общая лента журнала (без анкет участника): направление, инвестор, контрагент, статус и строка состояния. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
186 lines
14 KiB
HTML
186 lines
14 KiB
HTML
{{define "content"}}
|
|
{{template "depoProcsBanner" .}}
|
|
{{/* ===== Оператор-дашборд (Apple-стиль): приветствие → статус → плитки задач → сводка ===== */}}
|
|
|
|
<div class="hero">
|
|
<h1 class="hero-greeting">Добрый день</h1>
|
|
{{if .AllReady}}
|
|
<span class="hero-status ok">● Система готова к работе</span>
|
|
{{else}}
|
|
<div style="display:flex;align-items:center;gap:14px;flex-wrap:wrap">
|
|
<span class="hero-status warn">● Требуется настройка — не выполнено {{.NotReadyCount}} из {{.TotalCount}} шагов</span>
|
|
<a href="/admin/wizard" class="btn">Открыть мастер настройки →</a>
|
|
</div>
|
|
<p class="muted" style="margin:8px 0 0;font-size:13px">Осталось: {{range $i, $s := .NotReady}}{{if $i}}, {{end}}<a href="/admin/wizard?step={{$s.Step}}">{{$s.Title}}</a>{{end}}</p>
|
|
{{end}}
|
|
</div>
|
|
|
|
{{if and devOn .LKUrl}}
|
|
{{/* ===== Первичный тест интеграции с ЛК (режим разработки) ===== */}}
|
|
<div class="card" style="display:flex;gap:16px;align-items:center;flex-wrap:wrap">
|
|
<div style="width:42px;height:42px;border-radius:11px;background:var(--accent-weak);color:var(--accent);display:flex;align-items:center;justify-content:center;flex:none">
|
|
<svg viewBox="0 0 24 24" width="21" height="21" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>
|
|
</div>
|
|
<div style="flex:1;min-width:240px">
|
|
<div style="font-weight:640;font-size:15px">Первичный тест с личным кабинетом</div>
|
|
<div class="muted" style="margin-top:2px">Откройте ЛК, войдите и подайте заявку M2M — она придёт к нам и появится в разделе <a href="/admin/claims">«Переводы»</a>. Статус вернём в ЛK через callback.</div>
|
|
</div>
|
|
<a class="btn" href="{{.LKUrl}}" target="_blank" rel="noopener">Открыть тестовый ЛК →</a>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{/* ===== Крупные плитки задач ===== */}}
|
|
<div class="tiles">
|
|
{{/* В режиме разработки — симулятор перевода роботу НРД, у клиента — ручной ввод поручения */}}
|
|
<a {{if devOn}}href="#" onclick="document.getElementById('sim-modal').style.display='flex';return false"{{else}}href="/admin/manual"{{end}} class="tile brand">
|
|
<span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 8h12M12 4l4 4-4 4"/><path d="M20 16H8M12 20l-4-4 4-4"/></svg></span>
|
|
<span class="t-title">Новый перевод</span>
|
|
<span class="t-sub">{{if devOn}}Симулятор: сценарий робота + кол-во бумаг{{else}}Ручной ввод поручения клиента{{end}}</span>
|
|
<span class="t-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
|
|
</a>
|
|
<a href="/admin/journal" class="tile">
|
|
<span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6h12M8 12h12M8 18h12"/><path d="M3.5 6h.01M3.5 12h.01M3.5 18h.01"/></svg></span>
|
|
<span class="t-title">Переводы</span>
|
|
<span class="t-sub">{{.All.Out.Total}} исходящих · {{.All.In.Total}} входящих</span>
|
|
<span class="t-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
|
|
</a>
|
|
<a href="/admin/status" class="tile">
|
|
<span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l2.5 7 5-14 2.5 7h4"/></svg></span>
|
|
<span class="t-title">Диагностика</span>
|
|
<span class="t-sub">Состояние СКЗИ, ИШ и базы</span>
|
|
<span class="t-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
|
|
</a>
|
|
<a href="/admin/setup" class="tile">
|
|
<span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 8V3M5 21v-7M12 21v-9M12 8V3M19 21v-4M19 12V3"/><path d="M2.5 14h5M9.5 8h5M16.5 17h5"/></svg></span>
|
|
<span class="t-title">Настройка</span>
|
|
<span class="t-sub">Криптография, НРД, подключения</span>
|
|
<span class="t-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
|
|
</a>
|
|
</div>
|
|
|
|
{{if and devOn (can "settings")}}{{/* ===== Режим разработки: эмуляторы ===== */}}
|
|
<div class="tiles">
|
|
<a href="/admin/emulators" class="tile">
|
|
<span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/><path d="M4.9 4.9l2.1 2.1M17 17l2.1 2.1M19.1 4.9 17 7M7 17l-2.1 2.1"/></svg></span>
|
|
<span class="t-title">Эмулятор НРД</span>
|
|
<span class="t-sub">{{if .NSDEmuOn}}ВКЛЮЧЁН — в НРД ничего не отправляется{{else}}выключен{{end}}</span>
|
|
<span class="t-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
|
|
</a>
|
|
<a href="/admin/emulators" class="tile">
|
|
<span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M7 9h4M7 13h7"/></svg></span>
|
|
<span class="t-title">Эмулятор МНП QUIK</span>
|
|
<span class="t-sub">{{if .QuikRealCode}}ЗАПИСЬ в МНП на {{.QuikRealCode}} (реальные поручения){{else if .QuikEmuOn}}ВКЛЮЧЁН — в МНП ничего не пишется{{else}}выключен{{end}}</span>
|
|
<span class="t-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
|
|
</a>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{/* ===== Сводка по переводам: исходящие и входящие, за сегодня или за всё время ===== */}}
|
|
<style>
|
|
.period { display:inline-flex; border:1px solid var(--border); border-radius:9px; overflow:hidden; font-size:13px; }
|
|
.period a { padding:4px 12px; color:var(--muted); text-decoration:none; }
|
|
.period a.on { background:var(--accent-weak); color:var(--accent); font-weight:600; }
|
|
a.stat { display:block; color:inherit; text-decoration:none; }
|
|
.dirsplit { display:flex; flex-wrap:wrap; gap:4px 14px; margin-top:8px; font-size:12.5px; color:var(--muted); }
|
|
.dirsplit b { font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:14px; }
|
|
</style>
|
|
<div class="section-head" style="align-items:center;gap:10px;flex-wrap:wrap">
|
|
<h2>Переводы {{if eq .Period "today"}}за сегодня{{else}}за всё время{{end}}</h2>
|
|
<span class="period"><a href="/admin/?period=today"{{if eq .Period "today"}} class="on"{{end}}>Сегодня</a><a href="/admin/?period=all"{{if eq .Period "all"}} class="on"{{end}}>Всего</a></span>
|
|
</div>
|
|
<div class="grid" style="grid-template-columns:repeat(auto-fit,minmax(260px,1fr))">
|
|
<a class="stat accent" href="/admin/claims">
|
|
<div class="stat-label">↗ Исходящие — от нас в другие депозитарии</div>
|
|
<div class="stat-value">{{.Sum.Out.Total}}</div>
|
|
{{template "homeDirSplit" .Sum.Out}}
|
|
</a>
|
|
<a class="stat accent" href="/admin/incoming">
|
|
<div class="stat-label">↘ Входящие — к нам</div>
|
|
<div class="stat-value">{{.Sum.In.Total}}</div>
|
|
{{template "homeDirSplit" .Sum.In}}
|
|
</a>
|
|
</div>
|
|
|
|
{{/* ===== Последние переводы обоих направлений ===== */}}
|
|
<div class="section-head">
|
|
<h2>Последние переводы</h2>
|
|
<a href="/admin/journal">весь журнал →</a>
|
|
</div>
|
|
<div class="card">
|
|
{{if .Recent}}
|
|
<div style="overflow-x:auto">
|
|
<table>
|
|
<thead><tr><th>Время</th><th>Направление</th><th>Инвестор</th><th>Контрагент</th><th>ЦБ</th><th>Статус</th><th></th></tr></thead>
|
|
<tbody>
|
|
{{range .Recent}}
|
|
<tr>
|
|
<td class="num muted" style="white-space:nowrap">{{msk .Time}}</td>
|
|
<td>{{if eq .DirKind "out"}}<span class="badge" style="background:#e7f0fb;color:#1f4e79">↗ Исходящий</span>{{else}}<span class="badge" style="background:#e6f4ea;color:#1a7f37">↘ Входящий</span>{{end}}</td>
|
|
<td style="white-space:nowrap">{{.Investor}}</td>
|
|
<td>{{.Party}}</td>
|
|
<td class="num">{{.SecN}}</td>
|
|
<td><span class="badge {{.Status}}">{{.StatusText}}</span>{{if .Outcome}} <span class="badge {{if eq .Outcome "Принято"}}confirmed{{else if eq .Outcome "Отказано"}}rejected{{else}}awaiting_decision{{end}}">{{.Outcome}}</span>{{end}}{{if .Live.Text}}<div class="muted" style="font-size:12px;margin-top:2px">{{.Live.Text}}</div>{{end}}</td>
|
|
<td style="white-space:nowrap"><a href="{{.Href}}">открыть →</a></td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{else if eq .Period "today"}}
|
|
<p class="muted" style="margin:0">Сегодня переводов не было. <a href="/admin/?period=all">Показать за всё время</a></p>
|
|
{{else}}
|
|
<p class="muted" style="margin:0">Переводов ещё нет. {{if devOn}}Нажмите «Новый перевод», чтобы создать первый.{{else}}Они появятся с заявками из личного кабинета и от других депозитариев, а поручение клиента можно ввести вручную — «Новый перевод».{{end}}</p>
|
|
{{end}}
|
|
</div>
|
|
|
|
{{/* ===== События (компактно, если есть) ===== */}}
|
|
{{if .News}}
|
|
<div class="section-head">
|
|
<h2>События</h2>
|
|
<a href="/admin/news">все →</a>
|
|
</div>
|
|
<div class="card">
|
|
{{range .News}}
|
|
<div style="padding:9px 0;border-bottom:1px solid var(--border)">
|
|
<div style="font-weight:600;font-size:13.5px">
|
|
{{if eq .Kind "maintenance"}}{{end}}{{if eq .Kind "feature"}}{{end}}{{if eq .Kind "system"}}{{end}}{{if eq .Kind "doc-update"}}{{end}}{{.Title}}
|
|
</div>
|
|
{{if .Body}}<div class="muted" style="font-size:12px;margin-top:3px">{{.Body}}</div>{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{/* ===== Модалка-симулятор: тестовый перевод роботу НРД (режим разработки) ===== */}}
|
|
{{if devOn}}
|
|
<div id="sim-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;align-items:center;justify-content:center"
|
|
onclick="if(event.target===this)this.style.display='none'">
|
|
<div style="background:var(--card);border:1px solid var(--border);border-radius:14px;padding:24px;max-width:480px;width:92%;box-shadow:var(--shadow-lg)">
|
|
<h2 style="margin:0 0 4px">Новый перевод — симулятор</h2>
|
|
<p class="muted" style="margin:0 0 16px;font-size:13px">Отправка тестового пакета роботу НРД. Выберите сценарий и количество бумаг. Для сценария 3333 робот пришлёт встречный перевод — он появится во «Входящих» с уведомлением.</p>
|
|
<form method="post" action="/admin/setup/test-nsd" style="display:grid;gap:14px">
|
|
<label>Сценарий тестирования
|
|
<select name="scenario" style="width:100%;margin-top:4px">
|
|
<option value="2001">2001 — Принять все бумаги</option>
|
|
<option value="2002">2002 — Принять бумаги частично</option>
|
|
<option value="1111">1111 — Ответ с отказом</option>
|
|
<option value="3333">3333 — Робот принимающая сторона (пришлёт встречный перевод)</option>
|
|
</select>
|
|
</label>
|
|
<label>Количество ценных бумаг
|
|
<input type="number" name="securities_count" value="4" min="1" max="20" style="width:100%;margin-top:4px">
|
|
<span class="muted" style="font-size:12px">1–20. Эталонный набор — 4 бумаги; больше берётся циклически.</span>
|
|
</label>
|
|
<input type="hidden" name="channel" value="nsd">
|
|
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:4px">
|
|
<button type="button" class="btn btn-secondary" onclick="document.getElementById('sim-modal').style.display='none'">Отмена</button>
|
|
<button type="submit" class="btn btn-ok">Отправить</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|
|
{{/* исход переводов одного направления на дашборде (homeDir) */}}
|
|
{{define "homeDirSplit"}}<div class="dirsplit"><span><b style="color:var(--ok)">{{.Done}}</b> исполнено</span><span><b style="color:var(--warn)">{{.InProgress}}</b> в работе</span><span><b style="color:var(--err)">{{.Failed}}</b> отказ / истёк срок</span></div>{{end}}
|