altel-povtornye/index.html

219 lines
10 KiB
HTML
Raw Permalink 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.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Алтел — Все повторные обращения клиентов</title>
<style>
:root{--ink:#0F1218;--cyan:#00E5FF;--cyan-50:#E8FCFF;--white:#fff;--gray-500:#5B6573;--gray-100:#F2F4F7;--red:#FF4757;--orange:#FFA502;--green:#2ED573}
*{box-sizing:border-box;margin:0;padding:0}
body{font:17px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;color:var(--ink);background:var(--white)}
.container{max-width:1400px;margin:0 auto;padding:80px 24px}
.hero{background:var(--ink);color:var(--white);padding:100px 24px}
.hero h1{font-size:42px;font-weight:800;line-height:1.1;margin-bottom:20px}
.hero p{font-size:18px;color:#9aa3b2;max-width:900px;margin-bottom:32px}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:20px;margin-top:32px}
.stat-card{background:rgba(255,255,255,0.1);border-radius:12px;padding:20px;text-align:center}
.stat-card .num{font-size:42px;font-weight:800;color:var(--cyan);display:block}
.stat-card .label{color:#9aa3b2;font-size:13px;margin-top:8px;display:block;text-transform:uppercase;letter-spacing:1px}
.section{padding:80px 24px}
.section h2{font-size:32px;font-weight:700;margin-bottom:12px}
.section .subtitle{color:var(--gray-500);font-size:17px;margin-bottom:32px}
.controls{display:flex;gap:16px;margin-bottom:24px;flex-wrap:wrap}
.controls input{padding:12px 16px;border:2px solid var(--gray-100);border-radius:8px;font-size:16px;min-width:250px}
.controls input:focus{outline:none;border-color:var(--cyan)}
.controls select{padding:12px 16px;border:2px solid var(--gray-100);border-radius:8px;font-size:16px;background:var(--white)}
.table-container{overflow-x:auto;background:var(--gray-100);border-radius:16px;padding:24px}
table{width:100%;border-collapse:collapse;font-size:14px}
th{text-align:left;background:var(--ink);color:var(--white);padding:14px 12px;font-weight:700;font-size:13px;text-transform:uppercase;letter-spacing:0.5px;position:sticky;top:0}
td{padding:14px 12px;border-bottom:1px solid #e0e4e8;vertical-align:top}
tr:hover{background:#fff}
.company-col{font-weight:700;min-width:200px;font-size:15px}
.phone-col{font-family:monospace;color:var(--gray-500);white-space:nowrap}
.count-col{font-weight:800;font-size:18px;text-align:center}
.badge{display:inline-block;padding:6px 12px;border-radius:20px;font-size:12px;font-weight:700}
.badge-critical{background:var(--red);color:#fff}
.badge-high{background:var(--orange);color:#000}
.badge-medium{background:var(--cyan);color:var(--ink)}
.history-cell{font-size:13px}
.history-item{background:var(--white);border-left:3px solid var(--cyan);padding:8px 10px;margin-bottom:6px;border-radius:0 6px 6px 0}
.history-item:last-child{margin-bottom:0}
.history-date{font-weight:700;font-size:13px;margin-bottom:4px}
.history-details{display:flex;gap:12px;color:var(--gray-500);font-size:12px}
.history-details span{background:var(--gray-100);padding:3px 8px;border-radius:4px}
.days-badge{background:var(--gray-100);padding:4px 10px;border-radius:4px;font-size:12px;font-weight:700;display:inline-block}
.expand-btn{background:var(--cyan);border:none;color:var(--ink);padding:6px 14px;border-radius:6px;cursor:pointer;font-weight:700;font-size:12px}
.expand-btn:hover{background:#1be5ff}
.hidden-row{display:none}
@media (max-width:1024px){
.hero h1{font-size:32px}
.section h2{font-size:26px}
.container{padding:48px 20px}
table{font-size:13px}
}
</style>
</head>
<body>
<section class="hero">
<div class="container" style="padding:40px 0">
<h1>📋 История всех обращений клиентов Алтел</h1>
<p>Полная информация по клиентам с повторными обращениями: сколько раз обращался, все номера заявок и каналов, даты каждого обращения</p>
<div class="stats">
<div class="stat-card">
<span class="num" id="totalClients">0</span>
<span class="label">Клиентов с повторами</span>
</div>
<div class="stat-card">
<span class="num" id="maxRequests">0</span>
<span class="label">Макс. обращений</span>
</div>
<div class="stat-card">
<span class="num" id="criticalClients">0</span>
<span class="label">Критично (5+ раз)</span>
</div>
<div class="stat-card">
<span class="num" id="totalRequests">0</span>
<span class="label">Всего заявок</span>
</div>
</div>
</div>
</section>
<section class="section">
<div class="container">
<h2>🔍 Все клиенты с повторными обращениями</h2>
<p class="subtitle">Показаны только уникальные заявки (дубликаты исключены). Отсортировано по количеству обращений.</p>
<div class="controls">
<input type="text" id="searchInput" placeholder="🔍 Поиск по компании или телефону...">
<select id="filterSelect">
<option value="all">Все обращения</option>
<option value="5+">5+ обращений</option>
<option value="3-4">3-4 обращения</option>
<option value="2">2 обращения</option>
</select>
</div>
<div class="table-container">
<table>
<thead>
<tr>
<th style="width:60px">#</th>
<th>Компания</th>
<th>Телефон</th>
<th style="text-align:center">Раз обращался</th>
<th>Период</th>
<th>История заявок (№ заявки / № канала / Дата)</th>
</tr>
</thead>
<tbody id="summaryRow"></tbody>
<tbody id="tableBody"></tbody>
</table>
</div>
</div>
</section>
<script>
let data = null;
async function loadData() {
const response = await fetch('data.json?v=' + Date.now());
data = await response.json();
document.getElementById('totalClients').textContent = data.total_clients_with_repeats.toLocaleString('ru-RU');
document.getElementById('maxRequests').textContent = Math.max(...data.clients.map(c => c.total_requests)).toLocaleString('ru-RU');
document.getElementById('criticalClients').textContent = data.clients.filter(c => c.total_requests >= 5).length.toLocaleString('ru-RU');
document.getElementById('totalRequests').textContent = data.clients.reduce((sum, c) => sum + c.total_requests, 0).toLocaleString('ru-RU');
renderTable(data.clients);
}
function getBadge(count) {
if (count >= 5) return '<span class="badge badge-critical">Критично</span>';
if (count >= 3) return '<span class="badge badge-high">Высокий</span>';
return '<span class="badge badge-medium">Средний</span>';
}
function formatPhone(phone) {
const p = phone.toString();
return `+7 (${p.slice(0,3)}) ${p.slice(3,6)}-${p.slice(6,8)}-${p.slice(8)}`;
}
function renderTable(clients) {
// Добавляем строку с общей статистикой
const summaryRow = document.getElementById('summaryRow');
summaryRow.innerHTML = `
<tr style="background:var(--cyan-50);border-bottom:2px solid var(--ink)">
<td style="text-align:center;font-weight:700">📊</td>
<td colspan="2" style="font-weight:700">ИТОГО ПОВТОРНЫХ ОБРАЩЕНИЙ</td>
<td style="text-align:center;font-size:20px;font-weight:800;color:var(--red)">${clients.reduce((sum, c) => sum + c.total_requests, 0)}</td>
<td>
<div style="font-size:13px">Уникальных заявок: <strong>${data.total_unique_applications}</strong></div>
<div style="font-size:13px">Клиентов с повторами: <strong>${clients.length}</strong></div>
</td>
<td style="font-size:13px;color:var(--gray-500)">Все заявки показаны ниже в таблице</td>
</tr>
`;
const tbody = document.getElementById('tableBody');
tbody.innerHTML = '';
clients.forEach((client, index) => {
const tr = document.createElement('tr');
const historyHtml = client.requests.map((req, i) => `
<div class="history-item">
<div class="history-date">#${i + 1}. Заявка № ${req.id} &bull; ${req.date}</div>
<div class="history-details">
<span>Канал: ${req.channel}</span>
</div>
</div>
`).join('');
tr.innerHTML = `
<td style="text-align:center;font-weight:700;color:var(--gray-500)">${index + 1}</td>
<td class="company-col">${client.company}</td>
<td class="phone-col">${formatPhone(client.phone)}</td>
<td class="count-col">${getBadge(client.total_requests)}<div style="margin-top:6px;font-size:24px">${client.total_requests}</div></td>
<td>
<div style="font-weight:600">${client.first_date}</div>
<div style="color:var(--gray-500)">↓</div>
<div style="font-weight:600">${client.last_date}</div>
<div class="days-badge" style="margin-top:6px">${client.days_span} дн.</div>
</td>
<td class="history-cell">${historyHtml}</td>
`;
tbody.appendChild(tr);
});
}
document.getElementById('searchInput').addEventListener('input', (e) => {
const term = e.target.value.toLowerCase();
const filtered = data.clients.filter(c =>
c.company.toLowerCase().includes(term) ||
c.phone.toString().includes(term)
);
renderTable(filtered);
});
document.getElementById('filterSelect').addEventListener('change', (e) => {
const value = e.target.value;
let filtered = data.clients;
if (value === '5+') {
filtered = data.clients.filter(c => c.total_requests >= 5);
} else if (value === '3-4') {
filtered = data.clients.filter(c => c.total_requests >= 3 && c.total_requests < 5);
} else if (value === '2') {
filtered = data.clients.filter(c => c.total_requests === 2);
}
renderTable(filtered);
});
loadData();
</script>
</body>
</html>