Initial import with GitLab CI/CD and registry deploy flow

This commit is contained in:
Yera All
2026-04-02 17:05:45 +05:00
commit 5374c202d9
338 changed files with 81297 additions and 0 deletions
+1808
View File
File diff suppressed because it is too large Load Diff
+272
View File
@@ -0,0 +1,272 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>KonturCC Супервизор</title>
<link rel="icon" href="/operator/assets/favicon.svg" type="image/svg+xml" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700;800&family=IBM+Plex+Sans:wght@400;500;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/operator/assets/styles.css" />
</head>
<body>
<div class="app-shell">
<aside class="sidebar">
<div class="brand">
<div class="brand-mark">K</div>
<div>
<div class="brand-title">KonturCC</div>
<div class="brand-sub">Операционный контроль</div>
</div>
</div>
<nav class="nav-menu">
<div class="nav-group">
<div class="nav-label">Рабочие зоны</div>
<a class="nav-link" data-shell="operator" data-roles="admin,supervisor,operator,analyst" href="/operator"><span class="nav-bullet"></span>Оператор</a>
<a class="nav-link active" data-shell="supervisor" data-roles="admin,supervisor" href="/supervisor"><span class="nav-bullet"></span>Супервизор</a>
<a class="nav-link" data-shell="analyst" data-roles="admin,supervisor,analyst" href="/analyst"><span class="nav-bullet"></span>Аналитика</a>
<a class="nav-link" data-shell="admin" data-roles="admin" href="/admin"><span class="nav-bullet"></span>Администрирование</a>
</div>
<div class="nav-group">
<div class="nav-label">Блоки</div>
<a class="nav-link" href="#realtime"><span class="nav-bullet"></span>Оперативный срез</a>
<a class="nav-link" href="#liveCalls"><span class="nav-bullet"></span>Живые звонки</a>
<a class="nav-link" href="#agents"><span class="nav-bullet"></span>Агенты</a>
<a class="nav-link" href="#queues"><span class="nav-bullet"></span>Очереди</a>
<a class="nav-link" href="#knowledge"><span class="nav-bullet"></span>База знаний</a>
</div>
<div class="nav-group">
<div class="nav-label">Записи</div>
<a class="nav-link" href="#recordings"><span class="nav-bullet"></span>Записи</a>
</div>
</nav>
<div class="sidebar-footer">
<strong>Экран супервизора</strong>
<p>Сводка по агентам, очередям и KPI без захода в операторский экран.</p>
<button id="logoutBtn" class="btn ghost" type="button">Выйти</button>
</div>
</aside>
<section class="workspace">
<header class="workspace-topbar reveal">
<div class="search-box">
<input class="app-search" placeholder="Найти агента, очередь или KPI..." />
</div>
<div class="topbar-actions">
<div class="status-pill" id="gatewayStatus">Шлюз: проверка...</div>
<button class="icon-button" type="button" aria-label="Уведомления"></button>
<div class="profile-chip">
<div class="avatar-badge">SV</div>
<div class="profile-meta">
<div class="profile-name" id="profileName">Экран супервизора</div>
<div class="profile-role" id="profileRole">Операционный контроль</div>
</div>
</div>
</div>
</header>
<main class="layout">
<section class="page-hero reveal">
<p class="eyebrow">Операционный контур</p>
<h1>Пульт супервизора</h1>
<p class="hint">Операционный обзор: состояние команды, очередей и ключевых KPI.</p>
</section>
<section class="panel auth reveal" id="authPanel">
<h2>Сессия</h2>
<div class="row">
<label>Пользователь</label>
<input id="sessionUser" value="supervisor" />
</div>
<div class="row">
<label>Роль</label>
<select id="sessionRole">
<option value="supervisor" selected>Супервизор</option>
<option value="admin">Администратор</option>
<option value="operator">Оператор</option>
<option value="analyst">Аналитик</option>
</select>
</div>
<div class="row">
<label>Пароль</label>
<input id="sessionPassword" type="password" value="sup12345" />
</div>
<div class="actions">
<button id="loginBtn" class="btn">Войти</button>
<button id="corporateLoginBtn" class="btn ghost" type="button">Корпоративный вход</button>
<button id="refreshBtn" class="btn ghost">Обновить все</button>
</div>
<p class="hint" id="sessionInfo">Токен: отсутствует</p>
</section>
<section class="grid">
<article class="panel reveal" id="realtime">
<h2>Оперативный срез</h2>
<div class="actions compact-actions">
<button id="loadRealtimeBtn" class="btn ghost">Обновить срез</button>
<button id="loadKpiBtn" class="btn ghost">Обновить KPI</button>
</div>
<p class="hint">Этот блок нужен для оперативной проверки и технической диагностики на экране супервизора.</p>
<div id="realtimeSummary" class="summary-grid"></div>
<details class="details-block">
<summary>Технический ответ оперативного среза</summary>
<pre id="realtimeOutput" class="output"></pre>
</details>
<div id="kpiSummary" class="summary-grid"></div>
<details class="details-block">
<summary>Технический ответ KPI</summary>
<pre id="kpiOutput" class="output"></pre>
</details>
</article>
<article class="panel reveal" id="liveCalls">
<h2>Живые звонки Asterisk</h2>
<div class="actions compact-actions">
<button id="loadLiveCallsBtn" class="btn ghost">Обновить звонки</button>
</div>
<p class="hint">Показываются последние звонки, пришедшие от Asterisk.</p>
<ul id="liveCallsList" class="list"></ul>
</article>
<article class="panel reveal" id="agents">
<h2>Агенты</h2>
<div class="inline-form split-two">
<input id="agentId" placeholder="ID агента" value="supervisor_demo_agent" />
<select id="agentState">
<option value="READY">Готовы</option>
<option value="BUSY">Заняты</option>
<option value="BREAK">BREAK</option>
<option value="OFFLINE">OFFLINE</option>
</select>
</div>
<div class="inline-form compact">
<input id="agentQueueId" placeholder="Очередь" value="line2" />
<button id="setAgentBtn" class="btn">Обновить статус</button>
</div>
<div class="inline-form compact">
<button id="loadAgentsBtn" class="btn ghost">Показать агентов</button>
</div>
<ul id="agentsList" class="list"></ul>
</article>
<article class="panel reveal" id="queues">
<h2>Очередь</h2>
<div class="inline-form split-two">
<input id="queueMetricId" placeholder="ID очереди" value="line2" />
<input id="queueInQueue" placeholder="В очереди" type="number" value="2" />
</div>
<div class="inline-form compact">
<input id="queueAvgWait" placeholder="Среднее ожидание (сек)" type="number" value="18" />
<button id="saveQueueMetricsBtn" class="btn">Обновить очередь</button>
</div>
<p class="hint">Используйте это как быстрый операционный контроль для демонстрационного среза.</p>
<pre id="queueMetricsOutput" class="output"></pre>
</article>
<article class="panel reveal panel-span-full" id="knowledge">
<h2>База знаний</h2>
<p class="hint">Супервизор может вручную создать категорию, добавить статью и сразу обновить базу знаний для Voice AI.</p>
<div id="kbSummary" class="summary-grid"></div>
<div class="inline-form split-two">
<input id="kbCategoryName" placeholder="Новая категория" />
<input id="kbCategoryDescription" placeholder="Описание категории" />
</div>
<div class="inline-form compact">
<button id="createKbCategoryBtn" class="btn">Добавить категорию</button>
<button id="loadKbBtn" class="btn ghost" type="button">Обновить базу знаний</button>
</div>
<div class="inline-form split-two">
<select id="kbArticleCategory"></select>
<select id="kbArticleLanguage">
<option value="ru">RU</option>
<option value="kz">KZ</option>
</select>
</div>
<div class="inline-form compact">
<input id="kbArticleGroupId" placeholder="ID группы статей (связка RU/KZ)" />
</div>
<div class="inline-form split-two">
<input id="kbArticleTitle" placeholder="Заголовок статьи" />
</div>
<div class="inline-form compact">
<input id="kbArticleTags" placeholder="Теги через запятую" />
</div>
<div class="row">
<label for="kbArticleBody">Текст статьи</label>
<textarea id="kbArticleBody" rows="6" placeholder="Например: график работы, адреса, частые вопросы, правила маршрутизации..."></textarea>
</div>
<div class="actions compact-actions">
<button id="saveKbArticleBtn" class="btn">Сохранить статью</button>
<button id="resetKbArticleBtn" class="btn ghost" type="button">Новая статья</button>
</div>
<p class="hint" id="kbFormHint">Создайте новую статью или выберите существующую для редактирования.</p>
<div class="inline-form split-two">
<input id="kbSearchQuery" placeholder="Поиск по базе знаний" />
<button id="searchKbBtn" class="btn ghost" type="button">Искать</button>
</div>
<div class="inline-form split-two">
<div>
<h3>Категории</h3>
<ul id="kbCategoriesList" class="list"></ul>
</div>
<div>
<h3>Статьи</h3>
<ul id="kbArticlesList" class="list"></ul>
</div>
</div>
<details class="details-block">
<summary>Предпросмотр выбранной статьи</summary>
<pre id="kbArticlePreview" class="output"></pre>
</details>
</article>
<article class="panel reveal">
<h2>Лог действий</h2>
<p class="hint">Сверху всегда последнее действие супервизора.</p>
<pre id="eventLog" class="output tall"></pre>
</article>
<article class="panel reveal" id="recordings">
<h2>Записи</h2>
<div class="inline-form compact">
<input id="recordingEventId" placeholder="ID voice_event / обращения / звонка" />
<button id="importRecordingBtn" class="btn">Импорт / поиск</button>
</div>
<div class="inline-form split-two">
<input id="recordingCallId" placeholder="Фильтр по ID звонка" />
<input id="recordingInteractionId" placeholder="Фильтр по ID обращения" />
</div>
<div class="inline-form compact">
<select id="recordingStatus">
<option value="">Все</option>
<option value="ready">Готова</option>
<option value="archived">В архиве</option>
<option value="missing">Отсутствует</option>
</select>
<button id="loadRecordingsBtn" class="btn ghost">Показать записи</button>
<button id="archiveRecordingBtn" class="btn ghost" type="button">Архивировать</button>
</div>
<p class="hint">Для Asterisk запись обычно импортируется автоматически после завершения звонка.</p>
<ul id="recordingsList" class="list"></ul>
<div class="recording-detail">
<div class="hint" id="recordingSelectionHint">Выберите запись для предпросмотра.</div>
<pre id="recordingMetaOutput" class="output"></pre>
<audio id="recordingPlayer" controls preload="none"></audio>
<button id="downloadRecordingBtn" class="btn ghost" type="button">Скачать</button>
</div>
</article>
</section>
</main>
</section>
</div>
<script src="/supervisor/assets/app.js?v=track34-supervisor-ru-polish"></script>
</body>
</html>