399 lines
16 KiB
HTML
399 lines
16 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="tr">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>PulseDesk — Mini Destek Operasyon Merkezi</title>
|
||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='22' fill='%234f46e5'/%3E%3Ccircle cx='50' cy='50' r='16' fill='%23fff'/%3E%3C/svg%3E" />
|
||
<link rel="stylesheet" href="style.css" />
|
||
</head>
|
||
<body>
|
||
<div class="app">
|
||
|
||
<!-- ============ HEADER ============ -->
|
||
<header class="topbar">
|
||
<div class="brand">
|
||
<div class="brand-logo" aria-hidden="true">
|
||
<span class="pulse-dot"></span>
|
||
</div>
|
||
<div class="brand-text">
|
||
<h1>PulseDesk</h1>
|
||
<p>Mini Destek Operasyon Merkezi</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="topbar-actions">
|
||
<button type="button" id="btnTheme" class="btn btn-ghost" title="Tema değiştir" aria-label="Tema değiştir">
|
||
<span id="themeIcon">🌙</span> <span class="hide-sm">Tema</span>
|
||
</button>
|
||
<button type="button" id="btnReset" class="btn btn-ghost" title="Demo verileri sıfırla">
|
||
♻️ <span class="hide-sm">Demo Sıfırla</span>
|
||
</button>
|
||
<button type="button" id="btnNew" class="btn btn-primary">
|
||
+ <span class="hide-sm">Yeni Talep</span>
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="content">
|
||
|
||
<!-- ============ İSTATİSTİK KARTLARI ============ -->
|
||
<section class="stats" aria-label="İstatistikler">
|
||
<button type="button" class="stat-card" data-stat="total" title="Tüm talepleri göster">
|
||
<div class="stat-head">
|
||
<span class="stat-label">Toplam Talep</span>
|
||
<span class="stat-ico ico-total">📋</span>
|
||
</div>
|
||
<div class="stat-value" id="statTotal">0</div>
|
||
<div class="stat-foot">Sistemdeki tüm kayıtlar</div>
|
||
</button>
|
||
|
||
<button type="button" class="stat-card" data-stat="open" title="Açık talepleri göster">
|
||
<div class="stat-head">
|
||
<span class="stat-label">Açık Talepler</span>
|
||
<span class="stat-ico ico-open">🔓</span>
|
||
</div>
|
||
<div class="stat-value" id="statOpen">0</div>
|
||
<div class="stat-foot">Henüz işleme alınmadı</div>
|
||
</button>
|
||
|
||
<button type="button" class="stat-card" data-stat="progress" title="İşleniyor talepleri göster">
|
||
<div class="stat-head">
|
||
<span class="stat-label">İşleniyor</span>
|
||
<span class="stat-ico ico-progress">⚙️</span>
|
||
</div>
|
||
<div class="stat-value" id="statProgress">0</div>
|
||
<div class="stat-foot">Ekip üzerinde çalışıyor</div>
|
||
</button>
|
||
|
||
<button type="button" class="stat-card" data-stat="resolved" title="Çözülmüş talepleri göster">
|
||
<div class="stat-head">
|
||
<span class="stat-label">Çözülmüş</span>
|
||
<span class="stat-ico ico-resolved">✅</span>
|
||
</div>
|
||
<div class="stat-value" id="statResolved">0</div>
|
||
<div class="stat-foot">Kapatılan kayıtlar</div>
|
||
</button>
|
||
|
||
<button type="button" class="stat-card stat-critical" data-stat="critical" title="Kritik öncelikli talepleri göster">
|
||
<div class="stat-head">
|
||
<span class="stat-label">Kritik Öncelik</span>
|
||
<span class="stat-ico ico-critical">🚨</span>
|
||
</div>
|
||
<div class="stat-value" id="statCritical">0</div>
|
||
<div class="stat-foot">Acil müdahale gereken</div>
|
||
</button>
|
||
|
||
<button type="button" class="stat-card" data-stat="unassigned" title="Sorumlusu olmayan talepleri göster">
|
||
<div class="stat-head">
|
||
<span class="stat-label">Sahipsiz</span>
|
||
<span class="stat-ico ico-unassigned">👤</span>
|
||
</div>
|
||
<div class="stat-value" id="statUnassigned">0</div>
|
||
<div class="stat-foot">Sorumlu atanmamış</div>
|
||
</button>
|
||
</section>
|
||
|
||
<!-- ============ FİLTRE ÇUBUĞU ============ -->
|
||
<section class="panel filters" aria-label="Filtreler">
|
||
<div class="filters-row">
|
||
<div class="field field-search">
|
||
<label for="fSearch" class="field-label">Ara</label>
|
||
<div class="search-wrap">
|
||
<span class="search-ico" aria-hidden="true">🔍</span>
|
||
<input type="text" id="fSearch" placeholder="Başlık, müşteri, ID veya sorumlu ara..." autocomplete="off" />
|
||
<button type="button" id="btnClearSearch" class="search-clear" aria-label="Aramayı temizle" title="Aramayı temizle">✕</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label for="fStatus" class="field-label">Durum</label>
|
||
<select id="fStatus">
|
||
<option value="">Tümü</option>
|
||
<option value="acik">Açık</option>
|
||
<option value="isleniyor">İşleniyor</option>
|
||
<option value="cozuldu">Çözüldü</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label for="fPriority" class="field-label">Öncelik</label>
|
||
<select id="fPriority">
|
||
<option value="">Tümü</option>
|
||
<option value="kritik">Kritik</option>
|
||
<option value="yuksek">Yüksek</option>
|
||
<option value="orta">Orta</option>
|
||
<option value="dusuk">Düşük</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label for="fCategory" class="field-label">Kategori</label>
|
||
<select id="fCategory">
|
||
<option value="">Tümü</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label for="fSort" class="field-label">Sırala</label>
|
||
<select id="fSort">
|
||
<option value="newest">En yeni önce</option>
|
||
<option value="oldest">En eski önce</option>
|
||
<option value="priority">Öncelik (yüksek→düşük)</option>
|
||
<option value="priorityAsc">Öncelik (düşük→yüksek)</option>
|
||
<option value="title">Başlık (A→Z)</option>
|
||
<option value="updated">Son güncellenen</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="field field-action">
|
||
<label class="field-label"> </label>
|
||
<button type="button" id="btnClearFilters" class="btn btn-outline">Filtreleri Temizle</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="filters-meta">
|
||
<div id="activeChips" class="chips" aria-live="polite"></div>
|
||
<div class="result-count" id="resultCount">0 talep</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ LİSTE ============ -->
|
||
<section class="panel list-panel" aria-label="Talep listesi">
|
||
<div class="panel-head">
|
||
<h2>Destek Talepleri</h2>
|
||
<div class="view-toggle" role="group" aria-label="Görünüm">
|
||
<button type="button" class="vt-btn is-active" data-view="table" title="Tablo görünümü">☰ Tablo</button>
|
||
<button type="button" class="vt-btn" data-view="cards" title="Kart görünümü">▦ Kart</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="tableWrap" class="table-wrap">
|
||
<table class="tickets-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="col-id">ID</th>
|
||
<th class="col-title" data-sortkey="title">Başlık</th>
|
||
<th class="col-customer">Müşteri</th>
|
||
<th class="col-cat">Kategori</th>
|
||
<th class="col-pri">Öncelik</th>
|
||
<th class="col-status">Durum</th>
|
||
<th class="col-date">Tarih</th>
|
||
<th class="col-owner">Sorumlu</th>
|
||
<th class="col-ops">İşlem</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tableBody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div id="cardsWrap" class="cards-wrap" hidden></div>
|
||
|
||
<!-- Boş durum -->
|
||
<div id="emptyState" class="empty-state" hidden>
|
||
<div class="empty-ico">🗂️</div>
|
||
<h3 id="emptyTitle">Sonuç bulunamadı</h3>
|
||
<p id="emptyText">Arama veya filtre kriterlerinize uyan talep yok.</p>
|
||
<div class="empty-actions">
|
||
<button type="button" id="btnEmptyClear" class="btn btn-outline">Filtreleri Temizle</button>
|
||
<button type="button" id="btnEmptyNew" class="btn btn-primary">+ Yeni Talep</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<footer class="footer">
|
||
<span>PulseDesk · Veriler tarayıcınızın localStorage'ında saklanır.</span>
|
||
<span id="storageInfo" class="footer-dim"></span>
|
||
</footer>
|
||
</div>
|
||
|
||
<!-- ============ YENİ TALEP MODAL ============ -->
|
||
<div class="modal-overlay" id="newModal" hidden>
|
||
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="newModalTitle">
|
||
<div class="modal-head">
|
||
<h2 id="newModalTitle">Yeni Destek Talebi</h2>
|
||
<button type="button" class="modal-close" data-close="newModal" aria-label="Kapat">✕</button>
|
||
</div>
|
||
|
||
<form id="newForm" class="modal-body" novalidate>
|
||
<div class="form-row">
|
||
<div class="field">
|
||
<label for="nTitle">Başlık <span class="req">*</span></label>
|
||
<input type="text" id="nTitle" name="title" maxlength="120" placeholder="Örn: Ödeme ekranında hata alıyorum" />
|
||
<div class="err" data-err="title"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-grid">
|
||
<div class="field">
|
||
<label for="nCustomer">Müşteri Adı <span class="req">*</span></label>
|
||
<input type="text" id="nCustomer" name="customer" maxlength="80" placeholder="Örn: Ayşe Yılmaz" />
|
||
<div class="err" data-err="customer"></div>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label for="nCategory">Kategori <span class="req">*</span></label>
|
||
<select id="nCategory" name="category">
|
||
<option value="">Seçiniz...</option>
|
||
<option>Teknik Sorun</option>
|
||
<option>Faturalama</option>
|
||
<option>Hesap İşlemleri</option>
|
||
<option>Öneri / İstek</option>
|
||
<option>Kargo & Teslimat</option>
|
||
<option>Genel Soru</option>
|
||
</select>
|
||
<div class="err" data-err="category"></div>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label for="nPriority">Öncelik <span class="req">*</span></label>
|
||
<select id="nPriority" name="priority">
|
||
<option value="">Seçiniz...</option>
|
||
<option value="dusuk">Düşük</option>
|
||
<option value="orta">Orta</option>
|
||
<option value="yuksek">Yüksek</option>
|
||
<option value="kritik">Kritik</option>
|
||
</select>
|
||
<div class="err" data-err="priority"></div>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label for="nOwner">Sorumlu Kişi <span class="req">*</span></label>
|
||
<select id="nOwner" name="owner">
|
||
<option value="">Seçiniz...</option>
|
||
</select>
|
||
<div class="err" data-err="owner"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-row">
|
||
<div class="field">
|
||
<label for="nDescription">Açıklama <span class="req">*</span></label>
|
||
<textarea id="nDescription" name="description" rows="4" maxlength="600" placeholder="Sorunun detayını yazın (en az 10 karakter)..."></textarea>
|
||
<div class="char-count"><span id="descCount">0</span>/600</div>
|
||
<div class="err" data-err="description"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-error-banner" id="formBanner" hidden></div>
|
||
|
||
<div class="modal-foot">
|
||
<button type="button" class="btn btn-ghost" data-close="newModal">İptal</button>
|
||
<button type="submit" class="btn btn-primary" id="btnSaveTicket">Talebi Kaydet</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ DETAY MODAL ============ -->
|
||
<div class="modal-overlay" id="detailModal" hidden>
|
||
<div class="modal modal-lg" role="dialog" aria-modal="true" aria-labelledby="detailTitle">
|
||
<div class="modal-head">
|
||
<div class="detail-head-left">
|
||
<span class="ticket-id" id="detailId">#TKT-000</span>
|
||
<h2 id="detailTitle">Talep Başlığı</h2>
|
||
</div>
|
||
<button type="button" class="modal-close" data-close="detailModal" aria-label="Kapat">✕</button>
|
||
</div>
|
||
|
||
<div class="modal-body">
|
||
<div class="detail-badges" id="detailBadges"></div>
|
||
|
||
<div class="detail-grid">
|
||
<div class="detail-item">
|
||
<span class="detail-label">Müşteri</span>
|
||
<span class="detail-value" id="detailCustomer">-</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">Kategori</span>
|
||
<span class="detail-value" id="detailCategory">-</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">Oluşturulma</span>
|
||
<span class="detail-value" id="detailCreated">-</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">Son Güncelleme</span>
|
||
<span class="detail-value" id="detailUpdated">-</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="detail-desc">
|
||
<span class="detail-label">Açıklama</span>
|
||
<p id="detailDescription">-</p>
|
||
</div>
|
||
|
||
<div class="detail-controls">
|
||
<div class="field">
|
||
<label for="dStatus">Durum</label>
|
||
<select id="dStatus">
|
||
<option value="acik">Açık</option>
|
||
<option value="isleniyor">İşleniyor</option>
|
||
<option value="cozuldu">Çözüldü</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label for="dPriority">Öncelik</label>
|
||
<select id="dPriority">
|
||
<option value="dusuk">Düşük</option>
|
||
<option value="orta">Orta</option>
|
||
<option value="yuksek">Yüksek</option>
|
||
<option value="kritik">Kritik</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label for="dOwner">Sorumlu Kişi</label>
|
||
<select id="dOwner"></select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="status-flow">
|
||
<span class="status-flow-label">Hızlı durum akışı:</span>
|
||
<button type="button" class="btn btn-sm" data-set-status="acik">Açık</button>
|
||
<button type="button" class="btn btn-sm" data-set-status="isleniyor">İşleniyor</button>
|
||
<button type="button" class="btn btn-sm" data-set-status="cozuldu">Çözüldü</button>
|
||
</div>
|
||
|
||
<div class="activity">
|
||
<span class="detail-label">İşlem Geçmişi</span>
|
||
<ul id="detailLog" class="log-list"></ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal-foot modal-foot-split">
|
||
<button type="button" class="btn btn-danger" id="btnDeleteTicket">🗑️ Talebi Sil</button>
|
||
<div class="foot-right">
|
||
<button type="button" class="btn btn-ghost" data-close="detailModal">Kapat</button>
|
||
<button type="button" class="btn btn-primary" id="btnSaveDetail">Değişiklikleri Kaydet</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ ONAY MODAL ============ -->
|
||
<div class="modal-overlay" id="confirmModal" hidden>
|
||
<div class="modal modal-sm" role="dialog" aria-modal="true" aria-labelledby="confirmTitle">
|
||
<div class="modal-head">
|
||
<h2 id="confirmTitle">Emin misiniz?</h2>
|
||
<button type="button" class="modal-close" data-close="confirmModal" aria-label="Kapat">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<p id="confirmText">Bu işlem geri alınamaz.</p>
|
||
</div>
|
||
<div class="modal-foot">
|
||
<button type="button" class="btn btn-ghost" id="btnConfirmNo">İptal</button>
|
||
<button type="button" class="btn btn-danger" id="btnConfirmYes">Evet, Sil</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ TOAST ============ -->
|
||
<div id="toastContainer" class="toast-container" aria-live="polite" aria-atomic="false"></div>
|
||
|
||
<script src="app.js" defer></script>
|
||
<script src="ui.js" defer></script>
|
||
<script src="main.js" defer></script>
|
||
</body>
|
||
</html>
|