1fd56e205b
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Иерархический дашборд (3 уровня, drill-down). Этап 1: Командный центр + Финансы + Здоровье (переиспользуют существующие экраны как L3). Этап 2: Лиды + Заказ у поставщика. Механизм заказа задокументирован по коду (формула SupplierQuotaAllocator: max(max_спрос, ceil(Σ/3))), без маржи (по решению владельца). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
300 lines
21 KiB
HTML
300 lines
21 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Лидерра — Командный центр (макет)</title>
|
||
<style>
|
||
:root{
|
||
--teal:#0F6E56; --teal-d:#0a5443; --ivory:#F6F3EC; --noir:#012019;
|
||
--ink:#11201b; --muted:#6b7d76; --line:#e3ddd0; --card:#ffffff;
|
||
--green:#1f9d6b; --amber:#d4972a; --red:#cf4b46; --blue:#2f7fb5;
|
||
}
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{font-family:'Inter',system-ui,Segoe UI,Roboto,sans-serif;background:var(--ivory);color:var(--ink);display:flex;min-height:100vh}
|
||
.num{font-family:'JetBrains Mono','Consolas',monospace;font-variant-numeric:tabular-nums}
|
||
|
||
/* sidebar */
|
||
.side{width:230px;background:var(--noir);color:#cfe3db;flex-shrink:0;padding:0 0 20px}
|
||
.brand{padding:20px 22px 16px;font-weight:800;font-size:20px;color:#ffffff}
|
||
.brand b{color:#7fe0bf}
|
||
.brand .tag{display:block;font-size:11px;letter-spacing:3px;color:#5f8d7e;font-weight:600;margin-top:2px}
|
||
.nav a{display:flex;gap:10px;align-items:center;padding:10px 22px;color:#a9c6bb;text-decoration:none;font-size:14px;border-left:3px solid transparent}
|
||
.nav a.act{background:#0a2b22;color:#ffffff;border-left-color:#7fe0bf;font-weight:600}
|
||
.nav a:hover{background:#08241d;color:#ffffff}
|
||
.nav .sec{font-size:10px;letter-spacing:2px;color:#445566;padding:14px 22px 6px;text-transform:uppercase}
|
||
|
||
/* main */
|
||
.main{flex:1;min-width:0;display:flex;flex-direction:column}
|
||
.top{display:flex;align-items:center;justify-content:space-between;padding:16px 28px;border-bottom:1px solid var(--line);background:#ffffff}
|
||
.crumb{font-size:13px;color:var(--muted)}
|
||
.crumb b{color:var(--ink);font-size:18px;display:block}
|
||
.period{display:flex;gap:4px;background:var(--ivory);border:1px solid var(--line);border-radius:9px;padding:3px}
|
||
.period button{border:0;background:transparent;padding:6px 14px;border-radius:6px;font-size:13px;cursor:pointer;color:var(--muted)}
|
||
.period button.on{background:var(--teal);color:#ffffff;font-weight:600}
|
||
.user{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:600}
|
||
.ava{width:30px;height:30px;border-radius:50%;background:var(--red);color:#ffffff;display:grid;place-items:center;font-size:12px}
|
||
|
||
.wrap{padding:24px 28px;max-width:1200px}
|
||
.hint{font-size:13px;color:var(--muted);margin-bottom:16px}
|
||
.hint b{color:var(--teal)}
|
||
|
||
/* tiles */
|
||
.tiles{display:grid;grid-template-columns:1fr 1fr;gap:18px}
|
||
.tile{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:20px;cursor:pointer;transition:.15s;position:relative;box-shadow:0 1px 2px rgba(0,0,0,.03)}
|
||
.tile:hover{transform:translateY(-2px);box-shadow:0 8px 24px rgba(15,110,86,.12);border-color:#bbccdd}
|
||
.tile.sel{border-color:var(--teal);box-shadow:0 8px 24px rgba(15,110,86,.18)}
|
||
.tile h3{font-size:15px;display:flex;align-items:center;gap:8px;margin-bottom:14px}
|
||
.tile .ico{font-size:18px}
|
||
.light{margin-left:auto;font-size:12px;font-weight:700;padding:3px 10px;border-radius:20px}
|
||
.l-g{background:#e4f6ee;color:var(--green)} .l-a{background:#fbf0db;color:var(--amber)} .l-r{background:#fae3e2;color:var(--red)}
|
||
.rows{display:flex;flex-direction:column;gap:9px}
|
||
.row{display:flex;justify-content:space-between;align-items:baseline;font-size:14px}
|
||
.row .k{color:var(--muted)}
|
||
.row .v{font-weight:700}
|
||
.row .v.big{font-size:22px}
|
||
.row .v.r{color:var(--red)} .row .v.gr{color:var(--green)}
|
||
.more{margin-top:14px;font-size:12px;color:var(--teal);font-weight:600}
|
||
|
||
/* drill */
|
||
.drill{margin-top:22px;background:#ffffff;border:1px solid var(--line);border-radius:16px;padding:0;overflow:hidden;display:none}
|
||
.drill.show{display:block}
|
||
.dhead{padding:16px 22px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;background:#fbfaf6}
|
||
.dhead .t{font-weight:700;font-size:16px}
|
||
.dhead .bk{margin-left:auto;font-size:12px;color:var(--muted)}
|
||
.dbody{padding:22px}
|
||
.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:22px}
|
||
.kpi{background:var(--ivory);border-radius:12px;padding:14px}
|
||
.kpi .lab{font-size:12px;color:var(--muted)}
|
||
.kpi .val{font-size:20px;font-weight:800;margin-top:4px}
|
||
.kpi .val.r{color:var(--red)} .kpi .val.gr{color:var(--green)}
|
||
.grid2{display:grid;grid-template-columns:1.3fr 1fr;gap:22px}
|
||
.panel h4{font-size:13px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin-bottom:12px}
|
||
/* bar chart */
|
||
.chart{display:flex;align-items:flex-end;gap:8px;height:130px;padding:6px 0;border-bottom:1px solid var(--line)}
|
||
.bar{flex:1;display:flex;flex-direction:column;justify-content:flex-end;gap:3px;align-items:center}
|
||
.bar .b1{width:60%;background:var(--teal);border-radius:4px 4px 0 0}
|
||
.bar .b2{width:60%;background:#e0b15a;border-radius:4px 4px 0 0}
|
||
.bar .bl{font-size:10px;color:var(--muted)}
|
||
.leg{display:flex;gap:16px;font-size:12px;color:var(--muted);margin-top:8px}
|
||
.leg i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;vertical-align:middle}
|
||
table{width:100%;border-collapse:collapse;font-size:13px}
|
||
th{text-align:left;color:var(--muted);font-weight:600;font-size:11px;text-transform:uppercase;padding:8px 8px;border-bottom:1px solid var(--line)}
|
||
td{padding:10px 8px;border-bottom:1px solid #f0ece2}
|
||
tr.clk:hover{background:#f6fbf9;cursor:pointer}
|
||
.pill{font-size:11px;padding:2px 9px;border-radius:20px;font-weight:600}
|
||
.p-ok{background:#e4f6ee;color:var(--green)} .p-warn{background:#fbf0db;color:var(--amber)} .p-bad{background:#fae3e2;color:var(--red)}
|
||
/* health subsystems */
|
||
.subs{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px}
|
||
.sub{border:1px solid var(--line);border-radius:12px;padding:14px;display:flex;flex-direction:column;gap:6px}
|
||
.sub .nm{font-weight:600;font-size:14px;display:flex;align-items:center;gap:8px}
|
||
.dot{width:10px;height:10px;border-radius:50%}
|
||
.d-g{background:var(--green)} .d-a{background:var(--amber)} .d-r{background:var(--red)}
|
||
.sub .meta{font-size:12px;color:var(--muted)}
|
||
.soon{display:inline-block;font-size:11px;background:#eeeeee;color:#888888;padding:2px 8px;border-radius:10px;margin-left:6px}
|
||
.foot{padding:14px 28px;color:#99aaaa;font-size:11px;border-top:1px solid var(--line);margin-top:auto}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<aside class="side">
|
||
<div class="brand">Лидерра.<span class="tag">ADMIN</span></div>
|
||
<nav class="nav">
|
||
<a class="act" href="#">📊 Командный центр</a>
|
||
<div class="sec">Данные</div>
|
||
<a href="#" onclick="open_('fin');return false">👥 Тенанты</a>
|
||
<a href="#" onclick="open_('fin');return false">💳 Биллинг</a>
|
||
<a href="#">🏷️ Тарифная сетка</a>
|
||
<a href="#">₽ Цены поставщиков</a>
|
||
<div class="sec">Эксплуатация</div>
|
||
<a href="#" onclick="open_('health');return false">⚠️ Инциденты</a>
|
||
<a href="#">🧑🤝🧑 Impersonation</a>
|
||
<a href="#">⚙️ Система</a>
|
||
<a href="#" onclick="open_('health');return false">🔁 Интеграция с поставщиком</a>
|
||
<a href="#">🗂️ Проекты у поставщика</a>
|
||
<a href="#">🛡️ Обращения ПДн</a>
|
||
</nav>
|
||
</aside>
|
||
|
||
<div class="main">
|
||
<div class="top">
|
||
<div class="crumb">Админка<b>Командный центр</b></div>
|
||
<div class="period">
|
||
<button>Сегодня</button><button class="on">7 дней</button><button>30 дней</button>
|
||
</div>
|
||
<div class="user"><span class="ava">ДК</span> Дмитрий К.</div>
|
||
</div>
|
||
|
||
<div class="wrap">
|
||
<div class="hint">👆 Это <b>макет</b>. Кликните любую плитку — провалитесь в детали (Уровень 2). Цифры — для примера.</div>
|
||
|
||
<div class="tiles">
|
||
<!-- ФИНАНСЫ -->
|
||
<div class="tile sel" id="t-fin" onclick="open_('fin')">
|
||
<h3><span class="ico">💰</span> Финансы <span class="light l-r">1 в минусе</span></h3>
|
||
<div class="rows">
|
||
<div class="row"><span class="k">Пополнения за 7 дней</span><span class="v big num">320 000 ₽</span></div>
|
||
<div class="row"><span class="k">Списано за лиды</span><span class="v num">180 000 ₽</span></div>
|
||
<div class="row"><span class="k">Активных клиентов</span><span class="v num">5</span></div>
|
||
<div class="row"><span class="k">Новых за 7 дней</span><span class="v gr num">+2</span></div>
|
||
</div>
|
||
<div class="more">Открыть финансы →</div>
|
||
</div>
|
||
|
||
<!-- ЗДОРОВЬЕ -->
|
||
<div class="tile" id="t-health" onclick="open_('health')">
|
||
<h3><span class="ico">❤️</span> Здоровье портала <span class="light l-g">🟢 OK</span></h3>
|
||
<div class="rows">
|
||
<div class="row"><span class="k">Очереди / джобы</span><span class="v gr">работают</span></div>
|
||
<div class="row"><span class="k">Синхрон с поставщиком</span><span class="v gr">вчера 00:05 ✓</span></div>
|
||
<div class="row"><span class="k">Открытых инцидентов</span><span class="v num">0</span></div>
|
||
<div class="row"><span class="k">Последний сбой</span><span class="v">нет</span></div>
|
||
</div>
|
||
<div class="more">Открыть здоровье →</div>
|
||
</div>
|
||
|
||
<!-- ЛИДЫ -->
|
||
<div class="tile" id="t-leads" onclick="open_('leads')">
|
||
<h3><span class="ico">🎯</span> Лиды <span class="light l-g">🟢 чисто</span></h3>
|
||
<div class="rows">
|
||
<div class="row"><span class="k">Доставлено сегодня</span><span class="v big num">71</span></div>
|
||
<div class="row"><span class="k">Зависших</span><span class="v num">0</span></div>
|
||
<div class="row"><span class="k">Нераспределённых</span><span class="v num">0</span></div>
|
||
<div class="row"><span class="k">% доставки</span><span class="v gr num">100%</span></div>
|
||
</div>
|
||
<div class="more">Этап 2 →</div>
|
||
</div>
|
||
|
||
<!-- ЗАКАЗ У ПОСТАВЩИКА -->
|
||
<div class="tile" id="t-supply" onclick="open_('supply')">
|
||
<h3><span class="ico">📦</span> Заказ у поставщика <span class="light l-r">🔴 1 рассинхрон</span></h3>
|
||
<div class="rows">
|
||
<div class="row"><span class="k">Клиенты просят (Σ/день)</span><span class="v big num">250</span></div>
|
||
<div class="row"><span class="k">Надо по формуле</span><span class="v num">160</span></div>
|
||
<div class="row"><span class="k">Заказали по факту</span><span class="v num">175</span></div>
|
||
<div class="row"><span class="k">Групп с рассинхроном</span><span class="v r num">1</span></div>
|
||
</div>
|
||
<div class="more">Этап 2 →</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- DRILL: ФИНАНСЫ -->
|
||
<div class="drill show" id="d-fin">
|
||
<div class="dhead"><span>💰</span><span class="t">Финансы — детали</span><span class="bk">← клик по плитке возвращает наверх</span></div>
|
||
<div class="dbody">
|
||
<div class="kpis">
|
||
<div class="kpi"><div class="lab">Пополнения (7д)</div><div class="val">320 000 ₽</div></div>
|
||
<div class="kpi"><div class="lab">Списано за лиды (7д)</div><div class="val">180 000 ₽</div></div>
|
||
<div class="kpi"><div class="lab">Чистый приток</div><div class="val gr">+140 000 ₽</div></div>
|
||
<div class="kpi"><div class="lab">Клиентов в минусе</div><div class="val r">1</div></div>
|
||
</div>
|
||
<div class="grid2">
|
||
<div class="panel">
|
||
<h4>Пополнения и списания по дням</h4>
|
||
<div class="chart">
|
||
<div class="bar"><div class="b1" style="height:55px"></div><div class="b2" style="height:30px"></div><div class="bl">Пн</div></div>
|
||
<div class="bar"><div class="b1" style="height:40px"></div><div class="b2" style="height:35px"></div><div class="bl">Вт</div></div>
|
||
<div class="bar"><div class="b1" style="height:80px"></div><div class="b2" style="height:45px"></div><div class="bl">Ср</div></div>
|
||
<div class="bar"><div class="b1" style="height:30px"></div><div class="b2" style="height:50px"></div><div class="bl">Чт</div></div>
|
||
<div class="bar"><div class="b1" style="height:95px"></div><div class="b2" style="height:40px"></div><div class="bl">Пт</div></div>
|
||
<div class="bar"><div class="b1" style="height:20px"></div><div class="b2" style="height:25px"></div><div class="bl">Сб</div></div>
|
||
<div class="bar"><div class="b1" style="height:60px"></div><div class="b2" style="height:38px"></div><div class="bl">Вс</div></div>
|
||
</div>
|
||
<div class="leg"><span><i style="background:#0F6E56"></i>Пополнения</span><span><i style="background:#e0b15a"></i>Списания</span></div>
|
||
</div>
|
||
<div class="panel">
|
||
<h4>🔴 Требуют внимания (баланс кончается)</h4>
|
||
<table>
|
||
<tr><th>Клиент</th><th>Баланс</th><th>Хватит на</th></tr>
|
||
<tr class="clk"><td>ООО «Ромашка»</td><td class="num">−4 200 ₽</td><td><span class="pill p-bad">в минусе</span></td></tr>
|
||
<tr class="clk"><td>ИП Сидоров</td><td class="num">3 100 ₽</td><td><span class="pill p-warn">~1 день</span></td></tr>
|
||
<tr class="clk"><td>ООО «Вектор»</td><td class="num">18 900 ₽</td><td><span class="pill p-warn">~3 дня</span></td></tr>
|
||
</table>
|
||
<h4 style="margin-top:18px">Топ по обороту (7д)</h4>
|
||
<table>
|
||
<tr><th>Клиент</th><th>Пополнил</th><th>Лидов</th></tr>
|
||
<tr class="clk"><td>lkomega</td><td class="num">200 000 ₽</td><td class="num">712</td></tr>
|
||
<tr class="clk"><td>ООО «Вектор»</td><td class="num">80 000 ₽</td><td class="num">190</td></tr>
|
||
<tr class="clk"><td>ИП Сидоров</td><td class="num">40 000 ₽</td><td class="num">85</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- DRILL: ЗДОРОВЬЕ -->
|
||
<div class="drill" id="d-health">
|
||
<div class="dhead"><span>❤️</span><span class="t">Здоровье портала — детали</span><span class="bk">зелёное — всё ок</span></div>
|
||
<div class="dbody">
|
||
<div class="subs">
|
||
<div class="sub"><div class="nm"><span class="dot d-g"></span>Очереди / джобы</div><div class="meta">0 упавших за сутки · обрабатываются</div></div>
|
||
<div class="sub"><div class="nm"><span class="dot d-g"></span>Планировщик</div><div class="meta">все задачи по расписанию · посл. 00:05</div></div>
|
||
<div class="sub"><div class="nm"><span class="dot d-g"></span>Синхрон с поставщиком</div><div class="meta">вчера ✓ · 12 групп, 12 ок</div></div>
|
||
<div class="sub"><div class="nm"><span class="dot d-g"></span>Сверка CSV (дрейф)</div><div class="meta">дрейф 0% · мусора 56 (норм)</div></div>
|
||
<div class="sub"><div class="nm"><span class="dot d-a"></span>Вебхуки</div><div class="meta">1 неразобранный · посмотреть →</div></div>
|
||
<div class="sub"><div class="nm"><span class="dot d-g"></span>Инциденты</div><div class="meta">0 открытых</div></div>
|
||
</div>
|
||
<div style="margin-top:20px" class="panel">
|
||
<h4>Последние события эксплуатации</h4>
|
||
<table>
|
||
<tr><th>Когда</th><th>Что</th><th>Статус</th></tr>
|
||
<tr class="clk"><td class="num">сегодня 00:05</td><td>Вечерняя заливка поставщику</td><td><span class="pill p-ok">успех</span></td></tr>
|
||
<tr class="clk"><td class="num">сегодня 03:30</td><td>Резервная копия БД</td><td><span class="pill p-ok">успех</span></td></tr>
|
||
<tr class="clk"><td class="num">вчера 14:12</td><td>Сверка резервного канала (CSV)</td><td><span class="pill p-ok">дрейф 0%</span></td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- DRILL: ЛИДЫ (phase 2) -->
|
||
<div class="drill" id="d-leads">
|
||
<div class="dhead"><span>🎯</span><span class="t">Лиды — детали</span><span class="bk soon">Этап 2</span></div>
|
||
<div class="dbody">
|
||
<div class="kpis">
|
||
<div class="kpi"><div class="lab">Доставлено сегодня</div><div class="val">71</div></div>
|
||
<div class="kpi"><div class="lab">Зависших</div><div class="val gr">0</div></div>
|
||
<div class="kpi"><div class="lab">Нераспределённых</div><div class="val gr">0</div></div>
|
||
<div class="kpi"><div class="lab">Утечка (закуплено−доставлено)</div><div class="val gr">0</div></div>
|
||
</div>
|
||
<p style="color:var(--muted);font-size:13px">Здесь будет: распределение лидов по клиентам, поиск зависших/потерянных, % доставки по дням. Делаем на Этапе 2.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- DRILL: ЗАКАЗ У ПОСТАВЩИКА (phase 2) -->
|
||
<div class="drill" id="d-supply">
|
||
<div class="dhead"><span>📦</span><span class="t">Заказ у поставщика — детали</span><span class="bk soon">Этап 2</span></div>
|
||
<div class="dbody">
|
||
<div class="kpis">
|
||
<div class="kpi"><div class="lab">Клиенты просят (Σ/день)</div><div class="val">250</div></div>
|
||
<div class="kpi"><div class="lab">Надо по формуле</div><div class="val">160</div></div>
|
||
<div class="kpi"><div class="lab">Заказали по факту</div><div class="val">175</div></div>
|
||
<div class="kpi"><div class="lab">Рассинхронов</div><div class="val r">1</div></div>
|
||
</div>
|
||
<div class="panel">
|
||
<h4>По группам/проектам: спрос → формула → факт</h4>
|
||
<table>
|
||
<tr><th>Группа / проект</th><th>Клиенты просят (Σ)</th><th>Надо по формуле</th><th>Заказали по факту</th><th>Совпадает?</th></tr>
|
||
<tr class="clk"><td>Окна Москва</td><td class="num">150</td><td class="num">100</td><td class="num">100</td><td><span class="pill p-ok">🟢 да</span></td></tr>
|
||
<tr class="clk"><td>Кредиты СПб</td><td class="num">40</td><td class="num">40</td><td class="num">40</td><td><span class="pill p-ok">🟢 да</span></td></tr>
|
||
<tr class="clk"><td>Авто Казань</td><td class="num">60</td><td class="num">20</td><td class="num">35</td><td><span class="pill p-bad">🔴 рассинхрон</span></td></tr>
|
||
</table>
|
||
</div>
|
||
<p style="color:var(--muted);font-size:13px;margin-top:14px">Формула заказа: <b>max( самый крупный клиент ; ⌈сумма спроса ÷ 3⌉ )</b> — лид перепродаётся до 3 клиентов. 🔴 рассинхрон = «по факту» ≠ «по формуле» (правили лимит руками / синхрон 18:05 не прошёл). Делаем на Этапе 2.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="foot">Лидерра · Командный центр (макет для согласования вида) · цифры демонстрационные</div>
|
||
</div>
|
||
|
||
<script>
|
||
function open_(id){
|
||
['fin','health','leads','supply'].forEach(function(k){
|
||
document.getElementById('d-'+k).classList.toggle('show', k===id);
|
||
document.getElementById('t-'+k).classList.toggle('sel', k===id);
|
||
});
|
||
window.scrollTo({top:document.getElementById('d-'+id).offsetTop-20,behavior:'smooth'});
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|