deshbord-podderzhke-klientov/index.html

484 lines
25 KiB
HTML
Raw 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" data-theme="light">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Дашборд поддержки клиентов</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="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🎧</text></svg>">
<style>
.kt-ai-app { background: var(--kt-ai-bg); color: var(--kt-ai-fg); font-family: var(--kt-ai-font-sans); min-height: 100vh; }
.kt-ai-app-layout { display: grid; grid-template-columns: 240px 1fr; min-height: 100vh; }
.kt-ai-sidebar { background: var(--kt-ai-bg-soft); border-right: 1px solid var(--kt-ai-border); padding: var(--kt-ai-space-5); }
.kt-ai-main { padding: var(--kt-ai-space-6); overflow: auto; }
.kt-ai-sidebar-title { font-size: var(--kt-ai-text-sm); font-weight: var(--kt-ai-weight-semibold); color: var(--kt-ai-fg-muted); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: var(--kt-ai-space-4); }
.kt-ai-nav-item { display: flex; align-items: center; gap: var(--kt-ai-space-3); padding: var(--kt-ai-space-3) var(--kt-ai-space-3); border-radius: var(--kt-ai-radius-md); color: var(--kt-ai-fg); text-decoration: none; margin-bottom: var(--kt-ai-space-1); }
.kt-ai-nav-item:hover { background: var(--kt-ai-card-bg); }
.kt-ai-nav-item.active { background: var(--kt-ai-primary); color: #fff; }
.kt-ai-nav-icon { width: 20px; height: 20px; flex-shrink: 0; }
.kt-ai-topbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--kt-ai-space-6); padding-bottom: var(--kt-ai-space-4); border-bottom: 1px solid var(--kt-ai-border); }
.kt-ai-topbar-left { display: flex; align-items: center; gap: var(--kt-ai-space-4); }
.kt-ai-page-title { font-size: var(--kt-ai-text-2xl); font-weight: var(--kt-ai-weight-semibold); }
.kt-ai-kpi-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--kt-ai-space-4); margin-bottom: var(--kt-ai-space-6); }
.kt-ai-kpi { background: var(--kt-ai-card-bg); border: 1px solid var(--kt-ai-card-border); border-radius: var(--kt-ai-radius-xl); padding: var(--kt-ai-space-5); }
.kt-ai-kpi .value { font-size: var(--kt-ai-text-3xl); font-weight: var(--kt-ai-weight-bold); line-height: 1.2; }
.kt-ai-kpi .label { font-size: var(--kt-ai-text-sm); color: var(--kt-ai-fg-muted); margin-top: var(--kt-ai-space-2); }
.kt-ai-kpi .hint { font-size: var(--kt-ai-text-xs); color: var(--kt-ai-fg-faint); margin-top: var(--kt-ai-space-1); }
.kt-ai-kpi.trend-up .hint { color: var(--kt-ai-status-ok-fg); }
.kt-ai-kpi.trend-down .hint { color: var(--kt-ai-status-risk-fg); }
.kt-ai-cards-row { display: grid; grid-template-columns: 2fr 1fr; gap: var(--kt-ai-space-4); margin-bottom: var(--kt-ai-space-6); }
.kt-ai-card { background: var(--kt-ai-card-bg); border: 1px solid var(--kt-ai-card-border); border-radius: var(--kt-ai-radius-xl); padding: var(--kt-ai-space-5); }
.kt-ai-card-title { font-size: var(--kt-ai-text-lg); font-weight: var(--kt-ai-weight-semibold); margin-bottom: var(--kt-ai-space-4); }
.kt-ai-table-wrap { overflow-x: auto; }
.kt-ai-table { width: 100%; border-collapse: collapse; }
.kt-ai-table th { text-align: left; font-size: var(--kt-ai-text-xs); color: var(--kt-ai-fg-muted); text-transform: uppercase; letter-spacing: 0.04em; padding: var(--kt-ai-space-3) var(--kt-ai-space-3); border-bottom: 1px solid var(--kt-ai-border); }
.kt-ai-table td { padding: var(--kt-ai-space-3); border-bottom: 1px solid var(--kt-ai-border); font-size: var(--kt-ai-text-sm); }
.kt-ai-table tr:hover { background: var(--kt-ai-bg-soft); }
.kt-ai-table-num { text-align: right; font-variant-numeric: tabular-nums; }
.kt-ai-filters { display: flex; gap: var(--kt-ai-space-3); margin-bottom: var(--kt-ai-space-4); flex-wrap: wrap; align-items: center; }
.kt-ai-filter-group { display: flex; align-items: center; gap: var(--kt-ai-space-2); }
.kt-ai-filter-label { font-size: var(--kt-ai-text-sm); color: var(--kt-ai-fg-muted); }
.kt-ai-select { padding: var(--kt-ai-space-2) var(--kt-ai-space-3); border-radius: var(--kt-ai-radius-md); border: 1px solid var(--kt-ai-border); background: var(--kt-ai-bg); color: var(--kt-ai-fg); font-size: var(--kt-ai-text-sm); }
.kt-ai-operator-avatar { width: 32px; height: 32px; border-radius: var(--kt-ai-radius-full); background: var(--kt-ai-primary); color: #fff; display: flex; align-items: center; justify-content: center; font-size: var(--kt-ai-text-sm); font-weight: var(--kt-ai-weight-semibold); }
.kt-ai-chart-container { height: 200px; display: flex; align-items: flex-end; gap: 8px; padding-top: var(--kt-ai-space-4); }
.kt-ai-chart-bar { flex: 1; background: var(--kt-ai-chart-blue); border-radius: var(--kt-ai-radius-md) var(--kt-ai-radius-md) 0 0; min-width: 24px; position: relative; cursor: pointer; transition: opacity 0.2s; }
.kt-ai-chart-bar:hover { opacity: 0.8; }
.kt-ai-chart-bar[data-kt-tip]::after { content: attr(data-kt-tip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--kt-ai-fg); color: var(--kt-ai-bg); padding: 4px 8px; border-radius: var(--kt-ai-radius-md); font-size: var(--kt-ai-text-xs); white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity 0.2s; margin-bottom: 4px; }
.kt-ai-chart-bar:hover::after { opacity: 1; }
.kt-ai-chart-labels { display: flex; gap: 8px; margin-top: var(--kt-ai-space-2); }
.kt-ai-chart-label { flex: 1; text-align: center; font-size: var(--kt-ai-text-xs); color: var(--kt-ai-fg-muted); min-width: 24px; }
.kt-ai-empty { text-align: center; padding: var(--kt-ai-space-10); color: var(--kt-ai-fg-muted); }
.kt-ai-empty-icon { width: 64px; height: 64px; margin-bottom: var(--kt-ai-space-4); opacity: 0.5; }
.kt-ai-btn-sm { padding: var(--kt-ai-space-1) var(--kt-ai-space-3); font-size: var(--kt-ai-text-xs); }
.kt-ai-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 1000; }
.kt-ai-modal { background: var(--kt-ai-card-bg); border-radius: var(--kt-ai-radius-2xl); padding: var(--kt-ai-space-6); width: 100%; max-width: 480px; border: 1px solid var(--kt-ai-card-border); }
.kt-ai-modal-title { font-size: var(--kt-ai-text-xl); font-weight: var(--kt-ai-weight-semibold); margin-bottom: var(--kt-ai-space-4); }
.kt-ai-field { margin-bottom: var(--kt-ai-space-4); }
.kt-ai-field label { display: block; font-size: var(--kt-ai-text-sm); color: var(--kt-ai-fg-muted); margin-bottom: var(--kt-ai-space-2); }
.kt-ai-input, .kt-ai-textarea { width: 100%; padding: var(--kt-ai-space-2) var(--kt-ai-space-3); border-radius: var(--kt-ai-radius-md); border: 1px solid var(--kt-ai-border); background: var(--kt-ai-bg); color: var(--kt-ai-fg); font-size: var(--kt-ai-text-sm); font-family: inherit; }
.kt-ai-textarea { min-height: 100px; resize: vertical; }
.kt-ai-modal-actions { display: flex; gap: var(--kt-ai-space-3); justify-content: flex-end; margin-top: var(--kt-ai-space-6); }
.kt-ai-hidden { display: none !important; }
</style>
</head>
<body class="kt-ai-app" data-kt-data-mode="demo">
<div class="kt-ai-app-layout">
<aside class="kt-ai-sidebar">
<div class="kt-ai-sidebar-title">Навигация</div>
<nav>
<a href="#" class="kt-ai-nav-item active" data-page="dashboard">
<svg class="kt-ai-nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
Дашборд
</a>
<a href="#" class="kt-ai-nav-item" data-page="tickets">
<svg class="kt-ai-nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
Заявки
</a>
</nav>
</aside>
<main class="kt-ai-main">
<div class="kt-ai-topbar">
<div class="kt-ai-topbar-left">
<img src="https://code.vibe42.kz/tore/aitu/kt-logo.svg" alt="Казахтелеком" height="28">
<h1 class="kt-ai-page-title">Поддержка клиентов</h1>
<span class="kt-ai-chip" data-tone="orange">Демо-данные</span>
</div>
<div style="display:flex;align-items:center;gap:var(--kt-ai-space-3)">
<span class="kt-ai-chip" data-tone="green">Онлайн</span>
<div class="kt-ai-operator-avatar">А</div>
</div>
</div>
<!-- DASHBOARD PAGE -->
<div id="page-dashboard">
<div class="kt-ai-kpi-strip">
<div class="kt-ai-kpi trend-up">
<div class="value" id="kpi-total">0</div>
<div class="label">Всего обращений</div>
<div class="hint">↑ 12% за неделю</div>
</div>
<div class="kt-ai-kpi trend-up">
<div class="value" id="kpi-avg-time">0</div>
<div class="label">Среднее время ответа</div>
<div class="hint">↓ 8 мин быстрее</div>
</div>
<div class="kt-ai-kpi">
<div class="value" id="kpi-satisfaction">0%</div>
<div class="label">Удовлетворённость</div>
<div class="hint">За последний месяц</div>
</div>
<div class="kt-ai-kpi">
<div class="value" id="kpi-active">0</div>
<div class="label">В работе</div>
<div class="hint">Текущая нагрузка</div>
</div>
</div>
<div class="kt-ai-cards-row">
<div class="kt-ai-card">
<h2 class="kt-ai-card-title">Обращения по дням</h2>
<div class="kt-ai-chart-container" id="chart-bars"></div>
<div class="kt-ai-chart-labels" id="chart-labels"></div>
</div>
<div class="kt-ai-card">
<h2 class="kt-ai-card-title">По статусам</h2>
<div style="display:grid;gap:var(--kt-ai-space-3)">
<div style="display:flex;justify-content:space-between;align-items:center">
<span style="display:flex;align-items:center;gap:8px"><span class="kt-ai-chip" data-tone="blue">Новые</span></span>
<strong id="status-new">0</strong>
</div>
<div style="display:flex;justify-content:space-between;align-items:center">
<span style="display:flex;align-items:center;gap:8px"><span class="kt-ai-chip" data-tone="orange">В работе</span></span>
<strong id="status-progress">0</strong>
</div>
<div style="display:flex;justify-content:space-between;align-items:center">
<span style="display:flex;align-items:center;gap:8px"><span class="kt-ai-chip" data-tone="green">Завершённые</span></span>
<strong id="status-done">0</strong>
</div>
</div>
</div>
</div>
</div>
<!-- TICKETS PAGE -->
<div id="page-tickets" class="kt-ai-hidden">
<div class="kt-ai-card">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--kt-ai-space-4)">
<h2 class="kt-ai-card-title" style="margin:0">Все заявки</h2>
<button class="kt-ai-btn" data-variant="primary" id="btn-add-ticket">+ Новая заявка</button>
</div>
<div class="kt-ai-filters">
<div class="kt-ai-filter-group">
<span class="kt-ai-filter-label">Статус:</span>
<select class="kt-ai-select" id="filter-status">
<option value="all">Все</option>
<option value="new">Новые</option>
<option value="progress">В работе</option>
<option value="done">Завершённые</option>
</select>
</div>
<div class="kt-ai-filter-group">
<span class="kt-ai-filter-label">Оператор:</span>
<select class="kt-ai-select" id="filter-operator">
<option value="all">Все</option>
</select>
</div>
<div class="kt-ai-filter-group">
<span class="kt-ai-filter-label">Поиск:</span>
<input type="text" class="kt-ai-input" id="filter-search" placeholder="Клиент или тема" style="width:200px">
</div>
</div>
<div class="kt-ai-table-wrap">
<table class="kt-ai-table">
<thead>
<tr>
<th>ID</th>
<th>Клиент</th>
<th>Тема</th>
<th>Оператор</th>
<th>Статус</th>
<th>Дата</th>
<th>Действия</th>
</tr>
</thead>
<tbody id="tickets-body"></tbody>
</table>
</div>
<div id="empty-state" class="kt-ai-empty kt-ai-hidden">
<svg class="kt-ai-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
<p>Заявок не найдено</p>
<p style="font-size:var(--kt-ai-text-sm);margin-top:var(--kt-ai-space-1)">Измените фильтры или создайте новую заявку</p>
</div>
</div>
</div>
</main>
</div>
<!-- ADD TICKET MODAL -->
<div id="modal-add" class="kt-ai-modal-overlay kt-ai-hidden">
<div class="kt-ai-modal">
<h3 class="kt-ai-modal-title">Новая заявка</h3>
<form id="form-add-ticket">
<div class="kt-ai-field">
<label>Имя клиента</label>
<input type="text" class="kt-ai-input" name="client" required>
</div>
<div class="kt-ai-field">
<label>Тема обращения</label>
<input type="text" class="kt-ai-input" name="subject" required>
</div>
<div class="kt-ai-field">
<label>Описание</label>
<textarea class="kt-ai-textarea" name="description" required></textarea>
</div>
<div class="kt-ai-field">
<label>Оператор</label>
<select class="kt-ai-select" name="operator" required></select>
</div>
<div class="kt-ai-modal-actions">
<button type="button" class="kt-ai-btn" data-variant="ghost" onclick="closeModal()">Отмена</button>
<button type="submit" class="kt-ai-btn" data-variant="primary">Создать</button>
</div>
</form>
</div>
</div>
<script>
// Демо-данные и состояние
const OPERATORS = [
{ id: 'a', name: 'Анна К.', avatar: 'А' },
{ id: 'b', name: 'Бауыржан М.', avatar: 'Б' },
{ id: 'c', name: 'Светлана П.', avatar: 'С' },
{ id: 'd', name: 'Данияр Т.', avatar: 'Д' }
];
const DEMO_TICKETS = [
{ id: 1001, client: 'Иванов Петр', subject: 'Не работает интернет', description: 'Пропал сигнал с утра', operator: 'a', status: 'new', date: '2026-09-15', dayIndex: 0 },
{ id: 1002, client: 'Смирнова Елена', subject: 'Подключение ТВ', description: 'Хочу подключить цифровое ТВ', operator: 'b', status: 'progress', date: '2026-09-14', dayIndex: 1 },
{ id: 1003, client: 'Алиев Нурлан', subject: 'Смена тарифа', description: 'Перейти на безлимитный', operator: 'a', status: 'done', date: '2026-09-14', dayIndex: 1 },
{ id: 1004, client: 'Козлова Мария', subject: 'Ошибка в счёте', description: 'Неверная сумма в квитанции', operator: 'c', status: 'progress', date: '2026-09-13', dayIndex: 2 },
{ id: 1005, client: 'Омаров Асет', subject: 'Переезд', description: 'Перенос номера на новый адрес', operator: 'd', status: 'done', date: '2026-09-13', dayIndex: 2 },
{ id: 1006, client: 'Волкова Ольга', subject: 'Не приходит SMS', description: 'Коды подтверждения не доходят', operator: 'b', status: 'new', date: '2026-09-12', dayIndex: 3 },
{ id: 1007, client: 'Ибрагимов Рустам', subject: 'Роуминг', description: 'Настроить роуминг для Казахстана', operator: 'c', status: 'done', date: '2026-09-12', dayIndex: 3 },
{ id: 1008, client: 'Пак Юлия', subject: 'Блокировка', description: 'Разблокировать номер', operator: 'a', status: 'done', date: '2026-09-11', dayIndex: 4 },
{ id: 1009, client: 'Дюсенбаев Ержан', subject: 'Оплата', description: 'Не проходит оплата с карты', operator: 'd', status: 'progress', date: '2026-09-11', dayIndex: 4 },
{ id: 1010, client: 'Кузнецов Андрей', subject: 'Новый номер', description: 'Подобрать красивый номер', operator: 'b', status: 'new', date: '2026-09-10', dayIndex: 5 },
{ id: 1011, client: 'Абдрасулова Айгуль', subject: 'Домашний телефон', description: 'Подключить домашний телефон', operator: 'c', status: 'done', date: '2026-09-10', dayIndex: 5 },
{ id: 1012, client: 'Ли Дмитрий', subject: 'Wi-Fi роутер', description: 'Настройка роутера', operator: 'a', status: 'done', date: '2026-09-09', dayIndex: 6 }
];
const DAY_NAMES = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
const CHART_COLORS = ['var(--kt-ai-chart-blue)', 'var(--kt-ai-chart-green)', 'var(--kt-ai-chart-orange)', 'var(--kt-ai-chart-pink)', 'var(--kt-ai-chart-red)', 'var(--kt-ai-chart-salmon)', 'var(--kt-ai-chart-blue)'];
let tickets = [];
// Инициализация
function init() {
loadTickets();
renderOperatorFilter();
renderOperatorSelect();
updateDashboard();
renderTickets();
setupEventListeners();
}
function loadTickets() {
const stored = localStorage.getItem('kt_tickets');
if (stored) {
tickets = JSON.parse(stored);
} else {
tickets = [...DEMO_TICKETS];
saveTickets();
}
}
function saveTickets() {
localStorage.setItem('kt_tickets', JSON.stringify(tickets));
}
function renderOperatorFilter() {
const select = document.getElementById('filter-operator');
OPERATORS.forEach(op => {
const opt = document.createElement('option');
opt.value = op.id;
opt.textContent = op.name;
select.appendChild(opt);
});
}
function renderOperatorSelect() {
const selects = document.querySelectorAll('select[name="operator"]');
selects.forEach(select => {
select.innerHTML = '';
OPERATORS.forEach(op => {
const opt = document.createElement('option');
opt.value = op.id;
opt.textContent = op.name;
select.appendChild(opt);
});
});
}
function updateDashboard() {
const total = tickets.length;
const active = tickets.filter(t => t.status === 'new' || t.status === 'progress').length;
const done = tickets.filter(t => t.status === 'done').length;
const newCount = tickets.filter(t => t.status === 'new').length;
const progressCount = tickets.filter(t => t.status === 'progress').length;
document.getElementById('kpi-total').textContent = total;
document.getElementById('kpi-active').textContent = active;
document.getElementById('kpi-satisfaction').textContent = '94%';
document.getElementById('kpi-avg-time').textContent = '24 мин';
document.getElementById('status-new').textContent = newCount;
document.getElementById('status-progress').textContent = progressCount;
document.getElementById('status-done').textContent = done;
renderChart();
}
function renderChart() {
const byDay = [0, 0, 0, 0, 0, 0, 0];
tickets.forEach(t => {
if (t.dayIndex >= 0 && t.dayIndex < 7) byDay[t.dayIndex]++;
});
const max = Math.max(...byDay, 1);
const barsContainer = document.getElementById('chart-bars');
const labelsContainer = document.getElementById('chart-labels');
barsContainer.innerHTML = '';
labelsContainer.innerHTML = '';
byDay.forEach((count, i) => {
const height = (count / max) * 160 + 20;
const bar = document.createElement('div');
bar.className = 'kt-ai-chart-bar';
bar.style.height = height + 'px';
bar.style.background = CHART_COLORS[i];
bar.setAttribute('data-kt-tip', count + ' обращений');
barsContainer.appendChild(bar);
const label = document.createElement('div');
label.className = 'kt-ai-chart-label';
label.textContent = DAY_NAMES[i];
labelsContainer.appendChild(label);
});
}
function renderTickets() {
const statusFilter = document.getElementById('filter-status').value;
const operatorFilter = document.getElementById('filter-operator').value;
const searchFilter = document.getElementById('filter-search').value.toLowerCase();
let filtered = tickets.filter(t => {
if (statusFilter !== 'all' && t.status !== statusFilter) return false;
if (operatorFilter !== 'all' && t.operator !== operatorFilter) return false;
if (searchFilter && !t.client.toLowerCase().includes(searchFilter) && !t.subject.toLowerCase().includes(searchFilter)) return false;
return true;
});
const tbody = document.getElementById('tickets-body');
const emptyState = document.getElementById('empty-state');
if (filtered.length === 0) {
tbody.innerHTML = '';
emptyState.classList.remove('kt-ai-hidden');
} else {
emptyState.classList.add('kt-ai-hidden');
tbody.innerHTML = filtered.map(t => {
const op = OPERATORS.find(o => o.id === t.operator);
const statusChip = getStatusChip(t.status);
return `<tr>
<td>#${t.id}</td>
<td>${t.client}</td>
<td>${t.subject}</td>
<td><div class="kt-ai-operator-avatar" style="width:24px;height:24px;font-size:12px;display:inline-flex;margin-right:6px">${op.avatar}</div>${op.name}</td>
<td>${statusChip}</td>
<td class="kt-ai-table-num">${formatDate(t.date)}</td>
<td>
${t.status !== 'done' ? `<button class="kt-ai-btn kt-ai-btn-sm" data-variant="ghost" onclick="completeTicket(${t.id})">Завершить</button>` : ''}
<button class="kt-ai-btn kt-ai-btn-sm" data-variant="ghost" onclick="deleteTicket(${t.id})">Удалить</button>
</td>
</tr>`;
}).join('');
}
}
function getStatusChip(status) {
const map = {
new: '<span class="kt-ai-chip" data-tone="blue">Новая</span>',
progress: '<span class="kt-ai-chip" data-tone="orange">В работе</span>',
done: '<span class="kt-ai-chip" data-tone="green">Завершена</span>'
};
return map[status] || '';
}
function formatDate(dateStr) {
const d = new Date(dateStr);
return d.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short' });
}
function setupEventListeners() {
document.getElementById('filter-status').addEventListener('change', renderTickets);
document.getElementById('filter-operator').addEventListener('change', renderTickets);
document.getElementById('filter-search').addEventListener('input', renderTickets);
document.getElementById('btn-add-ticket').addEventListener('click', () => {
document.getElementById('modal-add').classList.remove('kt-ai-hidden');
});
document.getElementById('form-add-ticket').addEventListener('submit', (e) => {
e.preventDefault();
const form = e.target;
const newTicket = {
id: Math.max(...tickets.map(t => t.id), 1000) + 1,
client: form.client.value,
subject: form.subject.value,
description: form.description.value,
operator: form.operator.value,
status: 'new',
date: new Date().toISOString().split('T')[0],
dayIndex: new Date().getDay() === 0 ? 6 : new Date().getDay() - 1
};
tickets.unshift(newTicket);
saveTickets();
updateDashboard();
renderTickets();
closeModal();
form.reset();
});
document.querySelectorAll('.kt-ai-nav-item').forEach(item => {
item.addEventListener('click', (e) => {
e.preventDefault();
const page = item.dataset.page;
document.querySelectorAll('.kt-ai-nav-item').forEach(i => i.classList.remove('active'));
item.classList.add('active');
document.getElementById('page-dashboard').classList.add('kt-ai-hidden');
document.getElementById('page-tickets').classList.add('kt-ai-hidden');
document.getElementById('page-' + page).classList.remove('kt-ai-hidden');
});
});
}
function closeModal() {
document.getElementById('modal-add').classList.add('kt-ai-hidden');
}
function completeTicket(id) {
const ticket = tickets.find(t => t.id === id);
if (ticket) {
ticket.status = 'done';
saveTickets();
updateDashboard();
renderTickets();
}
}
function deleteTicket(id) {
if (confirm('Удалить заявку #' + id + '?')) {
tickets = tickets.filter(t => t.id !== id);
saveTickets();
updateDashboard();
renderTickets();
}
}
window.completeTicket = completeTicket;
window.deleteTicket = deleteTicket;
window.closeModal = closeModal;
init();
</script>
</body>
</html>