256 lines
13 KiB
HTML
256 lines
13 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru" data-theme="auto">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>WFM Калькулятор — Расчёт численности Контакт-центра</title>
|
||
<link rel="stylesheet" href="design-system/kt-ai-fonts.css">
|
||
<link rel="stylesheet" href="design-system/kt-ai-tokens.css">
|
||
<link rel="stylesheet" href="design-system/kt-ai-components.css">
|
||
<link rel="stylesheet" href="design-system/kt-ai-page.css">
|
||
<link rel="icon" href="design-system/brand/kt-ai-logo.png">
|
||
<style>
|
||
.wfm-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--kt-ai-space-6); }
|
||
.wfm-card { background: var(--kt-ai-card-bg); border: 1px solid var(--kt-ai-card-border); border-radius: var(--kt-ai-radius-3xl); padding: var(--kt-ai-space-6); }
|
||
.wfm-result { font-size: var(--kt-ai-text-3xl); font-weight: var(--kt-ai-weight-bold); color: var(--kt-ai-primary); }
|
||
.wfm-label { font-size: var(--kt-ai-text-sm); color: var(--kt-ai-fg-muted); margin-top: var(--kt-ai-space-2); }
|
||
.wfm-section { margin-bottom: var(--kt-ai-space-8); }
|
||
.wfm-section h3 { margin-bottom: var(--kt-ai-space-4); }
|
||
.results-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--kt-ai-space-4); margin-top: var(--kt-ai-space-6); }
|
||
.result-item { text-align: center; padding: var(--kt-ai-space-4); background: var(--kt-ai-bg-soft); border-radius: var(--kt-ai-radius-2xl); }
|
||
.result-value { font-size: var(--kt-ai-text-2xl); font-weight: var(--kt-ai-weight-semibold); }
|
||
.result-label { font-size: var(--kt-ai-text-sm); color: var(--kt-ai-fg-muted); margin-top: var(--kt-ai-space-1); }
|
||
.total-block { background: var(--kt-ai-primary); color: white; padding: var(--kt-ai-space-6); border-radius: var(--kt-ai-radius-3xl); margin-top: var(--kt-ai-space-6); }
|
||
.total-block .result-value { color: white; }
|
||
.total-block .result-label { color: rgba(255,255,255,0.8); }
|
||
.upload-area { border: 2px dashed var(--kt-ai-border); border-radius: var(--kt-ai-radius-3xl); padding: var(--kt-ai-space-8); text-align: center; cursor: pointer; transition: all 0.2s; }
|
||
.upload-area:hover { border-color: var(--kt-ai-primary); background: var(--kt-ai-bg-soft); }
|
||
.upload-area.dragover { border-color: var(--kt-ai-primary); background: var(--kt-ai-primary); color: white; }
|
||
.monthly-table { width: 100%; border-collapse: collapse; margin-top: var(--kt-ai-space-4); }
|
||
.monthly-table th, .monthly-table td { padding: var(--kt-ai-space-3); text-align: right; border-bottom: 1px solid var(--kt-ai-border); }
|
||
.monthly-table th { text-align: left; color: var(--kt-ai-fg-muted); font-weight: var(--kt-ai-weight-medium); }
|
||
.monthly-table tr:hover { background: var(--kt-ai-bg-soft); }
|
||
.tabs { display: flex; gap: var(--kt-ai-space-2); margin-bottom: var(--kt-ai-space-4); }
|
||
.tab { padding: var(--kt-ai-space-2) var(--kt-ai-space-4); border-radius: var(--kt-ai-radius-lg); cursor: pointer; color: var(--kt-ai-fg-muted); }
|
||
.tab.active { background: var(--kt-ai-primary); color: white; }
|
||
.mode-switch { display: none; }
|
||
.mode-switch.active { display: block; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<header class="kt-ai-pagehead">
|
||
<div class="kt-ai-wrap kt-ai-pagehead-in">
|
||
<div style="display:flex;align-items:center;gap:var(--kt-ai-space-3)">
|
||
<img src="design-system/brand/kt-ai-logo.png" alt="" height="22">
|
||
<strong>WFM Калькулятор</strong>
|
||
</div>
|
||
<span class="kt-ai-spacer"></span>
|
||
<a class="kt-ai-btn" data-variant="ghost" href="#history">История</a>
|
||
</div>
|
||
</header>
|
||
|
||
<section class="kt-ai-hero" data-align="center">
|
||
<div class="kt-ai-wrap">
|
||
<h1>Расчёт численности операторов Контакт-центра</h1>
|
||
<p class="kt-ai-hero-sub">Профессиональный инструмент WFM на основе формул Эрланга. Загрузите Excel с прогнозом или введите данные вручную.</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="kt-ai-section">
|
||
<div class="kt-ai-wrap">
|
||
<div class="kt-ai-section-head">
|
||
<h2>Режим расчёта</h2>
|
||
<p>Выберите способ ввода данных</p>
|
||
</div>
|
||
|
||
<div class="tabs" style="margin-top:var(--kt-ai-space-4);justify-content:center">
|
||
<div class="tab active" data-mode="manual"><svg class="kt-icon" style="vertical-align:middle"><use href="#pencil"></use></svg> Вручную</div>
|
||
<div class="tab" data-mode="upload"><svg class="kt-icon" style="vertical-align:middle"><use href="#upload"></use></svg> Загрузить Excel</div>
|
||
<div class="tab" data-mode="monthly"><svg class="kt-icon" style="vertical-align:middle"><use href="#chart"></use></svg> По месяцам</div>
|
||
</div>
|
||
|
||
<!-- Ручной ввод -->
|
||
<div id="manualMode" class="mode-switch active">
|
||
<form id="wfmForm" style="margin-top:var(--kt-ai-space-6)">
|
||
<div class="wfm-grid">
|
||
<div class="wfm-card">
|
||
<h3 style="margin-bottom:var(--kt-ai-space-4)"><svg class="kt-icon" aria-hidden="true"><use href="#megaphone"></use></svg> Входящие звонки</h3>
|
||
<div class="kt-ai-field">
|
||
<label>Количество звонков в месяц</label>
|
||
<input class="kt-ai-input" type="number" name="incomingCalls" value="151630" required>
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>AHT (мин)</label>
|
||
<input class="kt-ai-input" type="number" name="ahtIncoming" value="4.25" step="0.1" required>
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>Service Time (сек)</label>
|
||
<input class="kt-ai-input" type="number" name="serviceTimeIncoming" value="40" required>
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>Patience (сек)</label>
|
||
<input class="kt-ai-input" type="number" name="patienceIncoming" value="40" required>
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>Target SL (%)</label>
|
||
<input class="kt-ai-input" type="number" name="targetSL" value="80" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wfm-card">
|
||
<h3 style="margin-bottom:var(--kt-ai-space-4)"><svg class="kt-icon" aria-hidden="true"><use href="#megaphone"></use></svg> Исходящие звонки</h3>
|
||
<div class="kt-ai-field">
|
||
<label>Количество звонков в месяц</label>
|
||
<input class="kt-ai-input" type="number" name="outgoingCalls" value="20625">
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>AHT (мин)</label>
|
||
<input class="kt-ai-input" type="number" name="ahtOutgoing" value="4.5" step="0.1">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wfm-card">
|
||
<h3 style="margin-bottom:var(--kt-ai-space-4)"><svg class="kt-icon" aria-hidden="true"><use href="#mail"></use></svg> Неголосовые тикеты</h3>
|
||
<div class="kt-ai-field">
|
||
<label>Количество тикетов в месяц</label>
|
||
<input class="kt-ai-input" type="number" name="tickets" value="10426">
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>AHT (мин)</label>
|
||
<input class="kt-ai-input" type="number" name="ahtTickets" value="12" step="0.1">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wfm-card">
|
||
<h3 style="margin-bottom:var(--kt-ai-space-4)"><svg class="kt-icon" aria-hidden="true"><use href="#chat"></use></svg> Чаты</h3>
|
||
<div class="kt-ai-field">
|
||
<label>Количество чатов в месяц</label>
|
||
<input class="kt-ai-input" type="number" name="chats" value="14894">
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>AHT (мин)</label>
|
||
<input class="kt-ai-input" type="number" name="ahtChats" value="90" step="1">
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>Concurrency</label>
|
||
<input class="kt-ai-input" type="number" name="concurrency" value="4" min="1" max="10">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wfm-card">
|
||
<h3 style="margin-bottom:var(--kt-ai-space-4)"><svg class="kt-icon" aria-hidden="true"><use href="#settings"></use></svg> Общие параметры</h3>
|
||
<div class="kt-ai-field">
|
||
<label>Рабочих часов в месяц (FTE)</label>
|
||
<input class="kt-ai-input" type="number" name="fteHours" value="189" required>
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>Utilization</label>
|
||
<input class="kt-ai-input" type="number" name="utilization" value="0.86" step="0.01" min="0.1" max="1">
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>Плановые отсутствия (доля)</label>
|
||
<input class="kt-ai-input" type="number" name="plannedAbsence" value="0.1" step="0.01" min="0" max="0.5">
|
||
</div>
|
||
<div class="kt-ai-field">
|
||
<label>Неплановые отсутствия (доля)</label>
|
||
<input class="kt-ai-input" type="number" name="unplannedAbsence" value="0.05" step="0.01" min="0" max="0.5">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-top:var(--kt-ai-space-8);text-align:center">
|
||
<button class="kt-ai-btn" data-variant="primary" data-size="lg" type="submit">Рассчитать</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Загрузка Excel -->
|
||
<div id="uploadMode" class="mode-switch">
|
||
<div class="wfm-card" style="max-width:600px;margin:var(--kt-ai-space-6) auto">
|
||
<div class="upload-area" id="uploadArea">
|
||
<svg class="kt-icon kt-icon-lg" style="margin-bottom:var(--kt-ai-space-4)" aria-hidden="true"><use href="#upload"></use></svg>
|
||
<h3>Загрузите Excel файл</h3>
|
||
<p style="color:var(--kt-ai-fg-muted);margin:var(--kt-ai-space-2) 0">Перетащите файл или нажмите для выбора</p>
|
||
<p style="font-size:var(--kt-ai-text-sm);color:var(--kt-ai-fg-muted)">Формат: как в примере "Расчет численности ЦОО 2026 v1.xlsx"</p>
|
||
<input type="file" id="fileInput" accept=".xlsx,.xls" style="display:none">
|
||
</div>
|
||
<div id="uploadStatus" style="margin-top:var(--kt-ai-space-4);text-align:center"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- По месяцам -->
|
||
<div id="monthlyMode" class="mode-switch">
|
||
<div id="monthlyResults" style="margin-top:var(--kt-ai-space-6)">
|
||
<div class="wfm-card">
|
||
<h3>Загрузите Excel файл во вкладке "Загрузить Excel" для расчёта по месяцам</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="results" class="kt-ai-section" data-divider="true" style="display:none">
|
||
<div class="kt-ai-wrap">
|
||
<div class="kt-ai-section-head">
|
||
<h2>Результаты расчёта</h2>
|
||
<p>Требуемое количество операторов по каналам</p>
|
||
</div>
|
||
|
||
<div class="results-grid">
|
||
<div class="result-item">
|
||
<div class="result-value" id="resIncoming">-</div>
|
||
<div class="result-label">Входящие звонки</div>
|
||
<div class="result-label" id="resIncomingSL" style="color:var(--kt-ai-primary)"></div>
|
||
</div>
|
||
<div class="result-item">
|
||
<div class="result-value" id="resOutgoing">-</div>
|
||
<div class="result-label">Исходящие звонки</div>
|
||
</div>
|
||
<div class="result-item">
|
||
<div class="result-value" id="resTickets">-</div>
|
||
<div class="result-label">Неголосовые тикеты</div>
|
||
</div>
|
||
<div class="result-item">
|
||
<div class="result-value" id="resChats">-</div>
|
||
<div class="result-label">Чаты</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="total-block">
|
||
<div class="results-grid">
|
||
<div class="result-item" style="background:rgba(255,255,255,0.1)">
|
||
<div class="result-value" id="resTotalSchedule">-</div>
|
||
<div class="result-label">FTE в графике</div>
|
||
</div>
|
||
<div class="result-item" style="background:rgba(255,255,255,0.1)">
|
||
<div class="result-value" id="resTotalWithAbsence">-</div>
|
||
<div class="result-label">FTE в штате (с отсутствиями)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="history" class="kt-ai-section" data-divider="true">
|
||
<div class="kt-ai-wrap">
|
||
<div class="kt-ai-section-head">
|
||
<h2>История расчётов</h2>
|
||
<p>Последние 10 расчётов</p>
|
||
</div>
|
||
<div id="historyList" style="margin-top:var(--kt-ai-space-4)"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<footer class="kt-ai-wrap kt-ai-pagefoot">
|
||
<span>© 2026 WFM Calculator</span>
|
||
<span class="kt-ai-spacer"></span>
|
||
<span>На основе формул Эрланга</span>
|
||
</footer>
|
||
|
||
<script src="design-system/icons/kt-ai-icons.js"></script>
|
||
<script src="script.js"></script>
|
||
|
||
</body>
|
||
</html>
|