Spaces:
Paused
Paused
<html lang="fa" dir="rtl"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>آمار و تحلیل | سامانه حقوقی</title> | |
<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=Vazirmatn:wght@200;300;400;500;600;700;800;900&display=swap" rel="stylesheet"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.min.js"></script> | |
<!-- Load API Client --> | |
<script src="/static/js/api-client.js"></script> | |
<script src="/static/js/core.js"></script> | |
<style> | |
:root { | |
--text-primary: #0f172a; | |
--text-secondary: #475569; | |
--text-muted: #64748b; | |
--text-light: #ffffff; | |
--body-bg: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 50%, #cbd5e1 100%); | |
--card-bg: rgba(255, 255, 255, 0.95); | |
--glass-bg: rgba(255, 255, 255, 0.9); | |
--glass-border: rgba(148, 163, 184, 0.2); | |
--primary-gradient: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); | |
--secondary-gradient: linear-gradient(135deg, #06b6d4 0%, #0891b2 100%); | |
--success-gradient: linear-gradient(135deg, #10b981 0%, #047857 100%); | |
--warning-gradient: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); | |
--danger-gradient: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); | |
--shadow-xs: 0 1px 3px rgba(0, 0, 0, 0.05); | |
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08); | |
--shadow-md: 0 4px 15px rgba(0, 0, 0, 0.1); | |
--shadow-lg: 0 8px 25px rgba(0, 0, 0, 0.12); | |
--sidebar-width: 260px; | |
--border-radius: 12px; | |
--border-radius-sm: 8px; | |
--transition-smooth: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); | |
--transition-fast: all 0.15s ease-in-out; | |
--font-size-xs: 0.7rem; | |
--font-size-sm: 0.8rem; | |
--font-size-base: 0.9rem; | |
--font-size-lg: 1.1rem; | |
--font-size-xl: 1.25rem; | |
--font-size-2xl: 1.5rem; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
font-family: 'Vazirmatn', -apple-system, BlinkMacSystemFont, sans-serif; | |
background: var(--body-bg); | |
color: var(--text-primary); | |
line-height: 1.6; | |
overflow-x: hidden; | |
font-size: var(--font-size-base); | |
} | |
::-webkit-scrollbar { | |
width: 6px; | |
height: 6px; | |
} | |
::-webkit-scrollbar-track { | |
background: rgba(0, 0, 0, 0.02); | |
border-radius: 10px; | |
} | |
::-webkit-scrollbar-thumb { | |
background: var(--primary-gradient); | |
border-radius: 10px; | |
} | |
.dashboard-container { | |
display: flex; | |
min-height: 100vh; | |
width: 100%; | |
} | |
/* سایدبار مشابه صفحات قبلی */ | |
.sidebar { | |
width: var(--sidebar-width); | |
background: linear-gradient(135deg, | |
rgba(248, 250, 252, 0.98) 0%, | |
rgba(241, 245, 249, 0.95) 25%, | |
rgba(226, 232, 240, 0.98) 50%, | |
rgba(203, 213, 225, 0.95) 75%, | |
rgba(148, 163, 184, 0.1) 100%); | |
backdrop-filter: blur(25px); | |
-webkit-backdrop-filter: blur(25px); | |
padding: 1rem 0; | |
position: fixed; | |
height: 100vh; | |
right: 0; | |
top: 0; | |
z-index: 1000; | |
overflow-y: auto; | |
box-shadow: | |
0 0 0 1px rgba(59, 130, 246, 0.08), | |
-8px 0 32px rgba(59, 130, 246, 0.12), | |
inset 0 1px 0 rgba(255, 255, 255, 0.6); | |
border-left: 1px solid rgba(59, 130, 246, 0.15); | |
} | |
.sidebar-header { | |
padding: 0 1rem 1rem; | |
border-bottom: 1px solid rgba(59, 130, 246, 0.12); | |
margin-bottom: 1rem; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
background: linear-gradient(135deg, | |
rgba(255, 255, 255, 0.4) 0%, | |
rgba(248, 250, 252, 0.2) 100%); | |
margin: 0 0.5rem 1rem; | |
border-radius: var(--border-radius); | |
backdrop-filter: blur(10px); | |
} | |
.logo { | |
display: flex; | |
align-items: center; | |
gap: 0.6rem; | |
color: var(--text-primary); | |
text-decoration: none; | |
} | |
.logo-icon { | |
width: 2rem; | |
height: 2rem; | |
background: var(--primary-gradient); | |
border-radius: var(--border-radius-sm); | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-size: 1rem; | |
color: white; | |
} | |
.logo-text { | |
font-size: var(--font-size-lg); | |
font-weight: 700; | |
background: var(--primary-gradient); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
} | |
.nav-section { | |
margin-bottom: 1rem; | |
} | |
.nav-title { | |
padding: 0 1rem 0.4rem; | |
font-size: var(--font-size-xs); | |
font-weight: 600; | |
text-transform: uppercase; | |
letter-spacing: 0.5px; | |
color: var(--text-secondary); | |
} | |
.nav-menu { | |
list-style: none; | |
} | |
.nav-item { | |
margin: 0.15rem 0.5rem; | |
} | |
.nav-link { | |
display: flex; | |
align-items: center; | |
padding: 0.6rem 0.8rem; | |
color: var(--text-primary); | |
text-decoration: none; | |
border-radius: var(--border-radius-sm); | |
transition: var(--transition-smooth); | |
font-weight: 500; | |
font-size: var(--font-size-sm); | |
cursor: pointer; | |
border: 1px solid transparent; | |
} | |
.nav-link:hover { | |
color: var(--text-primary); | |
transform: translateX(-2px); | |
border-color: rgba(59, 130, 246, 0.15); | |
background: rgba(59, 130, 246, 0.05); | |
} | |
.nav-link.active { | |
background: var(--primary-gradient); | |
color: var(--text-light); | |
box-shadow: var(--shadow-md); | |
} | |
.nav-icon { | |
margin-left: 0.6rem; | |
width: 1rem; | |
text-align: center; | |
font-size: 0.9rem; | |
} | |
.nav-badge { | |
background: var(--danger-gradient); | |
color: white; | |
padding: 0.15rem 0.4rem; | |
border-radius: 10px; | |
font-size: var(--font-size-xs); | |
font-weight: 600; | |
margin-right: auto; | |
min-width: 1.2rem; | |
text-align: center; | |
} | |
/* محتوای اصلی */ | |
.main-content { | |
flex: 1; | |
margin-right: var(--sidebar-width); | |
padding: 1rem; | |
min-height: 100vh; | |
width: calc(100% - var(--sidebar-width)); | |
} | |
.page-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 2rem; | |
padding: 1rem 0; | |
border-bottom: 1px solid rgba(0, 0, 0, 0.1); | |
} | |
.page-title { | |
font-size: var(--font-size-2xl); | |
font-weight: 800; | |
background: var(--primary-gradient); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
display: flex; | |
align-items: center; | |
gap: 0.6rem; | |
} | |
.page-actions { | |
display: flex; | |
gap: 0.8rem; | |
} | |
.btn { | |
padding: 0.6rem 1.2rem; | |
border: none; | |
border-radius: var(--border-radius-sm); | |
font-family: inherit; | |
font-weight: 600; | |
cursor: pointer; | |
transition: var(--transition-smooth); | |
display: flex; | |
align-items: center; | |
gap: 0.5rem; | |
text-decoration: none; | |
font-size: var(--font-size-sm); | |
} | |
.btn-primary { | |
background: var(--primary-gradient); | |
color: white; | |
box-shadow: var(--shadow-sm); | |
} | |
.btn-primary:hover { | |
box-shadow: var(--shadow-md); | |
transform: translateY(-1px); | |
} | |
.btn-outline { | |
background: transparent; | |
color: var(--text-primary); | |
border: 1px solid rgba(59, 130, 246, 0.2); | |
} | |
.btn-outline:hover { | |
background: rgba(59, 130, 246, 0.05); | |
border-color: rgba(59, 130, 246, 0.4); | |
} | |
.btn-sm { | |
padding: 0.4rem 0.8rem; | |
font-size: var(--font-size-xs); | |
} | |
/* گرید تحلیلی */ | |
.analytics-grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); | |
gap: 1.5rem; | |
margin-bottom: 2rem; | |
} | |
.analytics-card { | |
background: var(--card-bg); | |
backdrop-filter: blur(10px); | |
-webkit-backdrop-filter: blur(10px); | |
border-radius: var(--border-radius); | |
padding: 1.5rem; | |
box-shadow: var(--shadow-md); | |
border: 1px solid rgba(255, 255, 255, 0.3); | |
transition: var(--transition-smooth); | |
position: relative; | |
overflow: hidden; | |
} | |
.analytics-card::before { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
height: 4px; | |
background: var(--primary-gradient); | |
} | |
.analytics-card:hover { | |
transform: translateY(-2px); | |
box-shadow: var(--shadow-lg); | |
} | |
.analytics-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 1rem; | |
} | |
.analytics-title { | |
font-size: var(--font-size-lg); | |
font-weight: 700; | |
color: var(--text-primary); | |
display: flex; | |
align-items: center; | |
gap: 0.5rem; | |
} | |
.analytics-actions { | |
display: flex; | |
gap: 0.5rem; | |
} | |
.chart-container { | |
height: 300px; | |
position: relative; | |
} | |
.chart-filters { | |
display: flex; | |
gap: 0.3rem; | |
margin-bottom: 1rem; | |
} | |
.chart-filter { | |
padding: 0.3rem 0.8rem; | |
border: none; | |
border-radius: 12px; | |
background: rgba(59, 130, 246, 0.08); | |
color: var(--text-secondary); | |
font-family: inherit; | |
font-size: var(--font-size-xs); | |
font-weight: 500; | |
cursor: pointer; | |
transition: var(--transition-fast); | |
} | |
.chart-filter:hover { | |
background: rgba(59, 130, 246, 0.12); | |
} | |
.chart-filter.active { | |
background: var(--primary-gradient); | |
color: white; | |
box-shadow: var(--shadow-sm); | |
} | |
/* آمار کلی */ | |
.overview-stats { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); | |
gap: 1rem; | |
margin-bottom: 2rem; | |
} | |
.stat-card { | |
background: var(--card-bg); | |
border-radius: var(--border-radius); | |
padding: 1.5rem; | |
text-align: center; | |
box-shadow: var(--shadow-sm); | |
border: 1px solid rgba(255, 255, 255, 0.3); | |
transition: var(--transition-smooth); | |
position: relative; | |
overflow: hidden; | |
} | |
.stat-card::before { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
height: 3px; | |
} | |
.stat-card.primary::before { background: var(--primary-gradient); } | |
.stat-card.success::before { background: var(--success-gradient); } | |
.stat-card.warning::before { background: var(--warning-gradient); } | |
.stat-card.danger::before { background: var(--danger-gradient); } | |
.stat-card:hover { | |
transform: translateY(-3px); | |
box-shadow: var(--shadow-lg); | |
} | |
.stat-value { | |
font-size: var(--font-size-2xl); | |
font-weight: 800; | |
color: var(--text-primary); | |
margin-bottom: 0.5rem; | |
} | |
.stat-label { | |
font-size: var(--font-size-sm); | |
color: var(--text-secondary); | |
margin-bottom: 0.5rem; | |
} | |
.stat-change { | |
font-size: var(--font-size-xs); | |
font-weight: 600; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
gap: 0.3rem; | |
} | |
.stat-change.positive { color: #059669; } | |
.stat-change.negative { color: #dc2626; } | |
/* ویجتهای پیشرفته */ | |
.advanced-widgets { | |
display: grid; | |
grid-template-columns: 1fr 1fr; | |
gap: 1.5rem; | |
margin-bottom: 2rem; | |
} | |
.widget { | |
background: var(--card-bg); | |
border-radius: var(--border-radius); | |
padding: 1.5rem; | |
box-shadow: var(--shadow-md); | |
border: 1px solid rgba(255, 255, 255, 0.3); | |
} | |
.widget-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 1rem; | |
} | |
.widget-title { | |
font-size: var(--font-size-lg); | |
font-weight: 600; | |
color: var(--text-primary); | |
} | |
/* جدول آمار */ | |
.stats-table { | |
width: 100%; | |
border-collapse: separate; | |
border-spacing: 0; | |
background: var(--card-bg); | |
border-radius: var(--border-radius); | |
overflow: hidden; | |
box-shadow: var(--shadow-sm); | |
} | |
.stats-table thead { | |
background: linear-gradient(135deg, rgba(59, 130, 246, 0.03), rgba(255, 255, 255, 0.1)); | |
} | |
.stats-table th { | |
padding: 1rem; | |
text-align: right; | |
font-weight: 600; | |
color: var(--text-primary); | |
font-size: var(--font-size-sm); | |
border-bottom: 1px solid rgba(0, 0, 0, 0.05); | |
} | |
.stats-table td { | |
padding: 0.8rem 1rem; | |
border-bottom: 1px solid rgba(0, 0, 0, 0.03); | |
font-size: var(--font-size-sm); | |
} | |
.stats-table tbody tr { | |
transition: all 0.2s ease; | |
} | |
.stats-table tbody tr:hover { | |
background: rgba(59, 130, 246, 0.02); | |
} | |
/* نمودار پیشرفت */ | |
.progress-widget { | |
padding: 1rem; | |
} | |
.progress-item { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 1rem; | |
} | |
.progress-item:last-child { | |
margin-bottom: 0; | |
} | |
.progress-info { | |
flex: 1; | |
margin-left: 1rem; | |
} | |
.progress-label { | |
font-size: var(--font-size-sm); | |
font-weight: 500; | |
color: var(--text-primary); | |
margin-bottom: 0.3rem; | |
} | |
.progress-bar { | |
width: 100%; | |
height: 6px; | |
background: rgba(0, 0, 0, 0.08); | |
border-radius: 3px; | |
overflow: hidden; | |
} | |
.progress-fill { | |
height: 100%; | |
border-radius: 3px; | |
transition: width 0.6s ease; | |
} | |
.progress-fill.primary { background: var(--primary-gradient); } | |
.progress-fill.success { background: var(--success-gradient); } | |
.progress-fill.warning { background: var(--warning-gradient); } | |
.progress-fill.danger { background: var(--danger-gradient); } | |
.progress-value { | |
font-size: var(--font-size-sm); | |
font-weight: 600; | |
color: var(--text-primary); | |
min-width: 3rem; | |
text-align: left; | |
} | |
/* محصولات اصلی */ | |
.main-analytics { | |
margin-bottom: 2rem; | |
} | |
.main-grid { | |
display: grid; | |
grid-template-columns: 2fr 1fr; | |
gap: 1.5rem; | |
margin-bottom: 1.5rem; | |
} | |
/* فیلترهای زمانی */ | |
.time-filters { | |
background: var(--card-bg); | |
border-radius: var(--border-radius); | |
padding: 1rem; | |
margin-bottom: 1.5rem; | |
box-shadow: var(--shadow-sm); | |
border: 1px solid rgba(255, 255, 255, 0.3); | |
} | |
.filter-row { | |
display: flex; | |
gap: 1rem; | |
align-items: center; | |
flex-wrap: wrap; | |
} | |
.filter-group { | |
display: flex; | |
flex-direction: column; | |
gap: 0.3rem; | |
} | |
.filter-label { | |
font-size: var(--font-size-xs); | |
font-weight: 600; | |
color: var(--text-secondary); | |
} | |
.filter-input, | |
.filter-select { | |
padding: 0.5rem; | |
border: 1px solid var(--glass-border); | |
border-radius: var(--border-radius-sm); | |
background: var(--glass-bg); | |
color: var(--text-primary); | |
font-family: inherit; | |
font-size: var(--font-size-sm); | |
transition: var(--transition-smooth); | |
} | |
.filter-input:focus, | |
.filter-select:focus { | |
outline: none; | |
border-color: #3b82f6; | |
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); | |
} | |
/* متریکهای زنده */ | |
.live-metrics { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
gap: 1rem; | |
margin-bottom: 1.5rem; | |
} | |
.live-metric { | |
background: var(--card-bg); | |
border-radius: var(--border-radius); | |
padding: 1rem; | |
text-align: center; | |
box-shadow: var(--shadow-sm); | |
border: 1px solid rgba(255, 255, 255, 0.3); | |
position: relative; | |
} | |
.live-metric::before { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
height: 3px; | |
background: var(--success-gradient); | |
} | |
.live-value { | |
font-size: var(--font-size-xl); | |
font-weight: 700; | |
color: var(--text-primary); | |
margin-bottom: 0.3rem; | |
} | |
.live-label { | |
font-size: var(--font-size-xs); | |
color: var(--text-secondary); | |
text-transform: uppercase; | |
letter-spacing: 0.5px; | |
} | |
.live-indicator { | |
position: absolute; | |
top: 0.5rem; | |
left: 0.5rem; | |
width: 8px; | |
height: 8px; | |
background: #10b981; | |
border-radius: 50%; | |
animation: pulse 2s infinite; | |
} | |
@keyframes pulse { | |
0%, 100% { opacity: 1; } | |
50% { opacity: 0.5; } | |
} | |
/* Toast Notifications */ | |
.toast-container { | |
position: fixed; | |
top: 1rem; | |
left: 1rem; | |
z-index: 10001; | |
display: flex; | |
flex-direction: column; | |
gap: 0.5rem; | |
} | |
.toast { | |
background: var(--card-bg); | |
border-radius: var(--border-radius-sm); | |
padding: 1rem 1.5rem; | |
box-shadow: var(--shadow-lg); | |
border-left: 4px solid; | |
display: flex; | |
align-items: center; | |
gap: 0.8rem; | |
min-width: 300px; | |
transform: translateX(-100%); | |
transition: all 0.3s ease; | |
} | |
.toast.show { | |
transform: translateX(0); | |
} | |
.toast.success { border-left-color: #10b981; } | |
.toast.error { border-left-color: #ef4444; } | |
.toast.warning { border-left-color: #f59e0b; } | |
.toast.info { border-left-color: #3b82f6; } | |
.toast-icon { | |
font-size: 1.2rem; | |
} | |
.toast.success .toast-icon { color: #10b981; } | |
.toast.error .toast-icon { color: #ef4444; } | |
.toast.warning .toast-icon { color: #f59e0b; } | |
.toast.info .toast-icon { color: #3b82f6; } | |
.toast-content { | |
flex: 1; | |
} | |
.toast-title { | |
font-weight: 600; | |
font-size: var(--font-size-sm); | |
margin-bottom: 0.2rem; | |
} | |
.toast-message { | |
font-size: var(--font-size-xs); | |
color: var(--text-secondary); | |
} | |
.toast-close { | |
background: none; | |
border: none; | |
color: var(--text-secondary); | |
cursor: pointer; | |
font-size: 1rem; | |
transition: var(--transition-fast); | |
} | |
.toast-close:hover { | |
color: var(--text-primary); | |
} | |
/* واکنشگرایی */ | |
@media (max-width: 992px) { | |
.sidebar { | |
transform: translateX(100%); | |
transition: transform 0.3s ease; | |
} | |
.sidebar.open { | |
transform: translateX(0); | |
} | |
.main-content { | |
margin-right: 0; | |
width: 100%; | |
padding: 1rem; | |
} | |
.analytics-grid { | |
grid-template-columns: 1fr; | |
} | |
.main-grid { | |
grid-template-columns: 1fr; | |
} | |
.advanced-widgets { | |
grid-template-columns: 1fr; | |
} | |
.filter-row { | |
flex-direction: column; | |
align-items: stretch; | |
} | |
} | |
@media (max-width: 768px) { | |
.main-content { | |
padding: 0.8rem; | |
} | |
.overview-stats { | |
grid-template-columns: repeat(2, 1fr); | |
} | |
.live-metrics { | |
grid-template-columns: 1fr; | |
} | |
.chart-container { | |
height: 250px; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div class="dashboard-container"> | |
<!-- سایدبار --> | |
<aside class="sidebar" id="sidebar"> | |
<div class="sidebar-header"> | |
<a href="/" class="logo"> | |
<div class="logo-icon"> | |
<i class="fas fa-scale-balanced"></i> | |
</div> | |
<div class="logo-text">سامانه حقوقی</div> | |
</a> | |
</div> | |
<nav> | |
<div class="nav-section"> | |
<h6 class="nav-title">داشبورد</h6> | |
<ul class="nav-menu"> | |
<li class="nav-item"> | |
<a href="/" class="nav-link"> | |
<i class="fas fa-chart-pie nav-icon"></i> | |
<span>نمای کلی</span> | |
</a> | |
</li> | |
</ul> | |
</div> | |
<div class="nav-section"> | |
<h6 class="nav-title">مدیریت اسناد</h6> | |
<ul class="nav-menu"> | |
<li class="nav-item"> | |
<a href="/static/documents.html" class="nav-link"> | |
<i class="fas fa-file-alt nav-icon"></i> | |
<span>مدیریت اسناد</span> | |
<span class="nav-badge" id="totalDocumentsBadge">6</span> | |
</a> | |
</li> | |
<li class="nav-item"> | |
<a href="/static/upload.html" class="nav-link"> | |
<i class="fas fa-cloud-upload-alt nav-icon"></i> | |
<span>آپلود فایل</span> | |
</a> | |
</li> | |
<li class="nav-item"> | |
<a href="/static/search.html" class="nav-link"> | |
<i class="fas fa-search nav-icon"></i> | |
<span>جستجو</span> | |
</a> | |
</li> | |
</ul> | |
</div> | |
<div class="nav-section"> | |
<h6 class="nav-title">ابزارها</h6> | |
<ul class="nav-menu"> | |
<li class="nav-item"> | |
<a href="/static/scraping.html" class="nav-link"> | |
<i class="fas fa-globe nav-icon"></i> | |
<span>استخراج محتوا</span> | |
</a> | |
</li> | |
<li class="nav-item"> | |
<a href="/static/analytics.html" class="nav-link active"> | |
<i class="fas fa-chart-line nav-icon"></i> | |
<span>آمار و تحلیل</span> | |
</a> | |
</li> | |
<li class="nav-item"> | |
<a href="/static/reports.html" class="nav-link"> | |
<i class="fas fa-file-export nav-icon"></i> | |
<span>گزارشها</span> | |
</a> | |
</li> | |
</ul> | |
</div> | |
<div class="nav-section"> | |
<h6 class="nav-title">تنظیمات</h6> | |
<ul class="nav-menu"> | |
<li class="nav-item"> | |
<a href="/static/settings.html" class="nav-link"> | |
<i class="fas fa-cog nav-icon"></i> | |
<span>تنظیمات</span> | |
</a> | |
</li> | |
<li class="nav-item"> | |
<a href="#" class="nav-link"> | |
<i class="fas fa-sign-out-alt nav-icon"></i> | |
<span>خروج</span> | |
</a> | |
</li> | |
</ul> | |
</div> | |
</nav> | |
</aside> | |
<!-- محتوای اصلی --> | |
<main class="main-content"> | |
<!-- هدر صفحه --> | |
<header class="page-header"> | |
<h1 class="page-title"> | |
<i class="fas fa-chart-line"></i> | |
آمار و تحلیل پیشرفته | |
</h1> | |
<div class="page-actions"> | |
<button type="button" class="btn btn-outline" onclick="exportAnalytics()"> | |
<i class="fas fa-download"></i> | |
خروجی گزارش | |
</button> | |
<button type="button" class="btn btn-primary" onclick="refreshAllAnalytics()"> | |
<i class="fas fa-sync-alt"></i> | |
بروزرسانی همه | |
</button> | |
</div> | |
</header> | |
<!-- فیلترهای زمانی --> | |
<section class="time-filters"> | |
<div class="filter-row"> | |
<div class="filter-group"> | |
<label class="filter-label">بازه زمانی</label> | |
<select class="filter-select" id="timeRange" onchange="updateTimeRange()"> | |
<option value="today">امروز</option> | |
<option value="week" selected>هفته گذشته</option> | |
<option value="month">ماه گذشته</option> | |
<option value="quarter">سه ماه گذشته</option> | |
<option value="year">سال گذشته</option> | |
<option value="custom">بازه دلخواه</option> | |
</select> | |
</div> | |
<div class="filter-group"> | |
<label class="filter-label">از تاریخ</label> | |
<input type="date" class="filter-input" id="startDate"> | |
</div> | |
<div class="filter-group"> | |
<label class="filter-label">تا تاریخ</label> | |
<input type="date" class="filter-input" id="endDate"> | |
</div> | |
<div class="filter-group"> | |
<label class="filter-label">نوع داده</label> | |
<select class="filter-select" id="dataType" onchange="updateDataType()"> | |
<option value="all">همه دادهها</option> | |
<option value="documents">اسناد</option> | |
<option value="users">کاربران</option> | |
<option value="system">سیستم</option> | |
</select> | |
</div> | |
<button type="button" class="btn btn-primary btn-sm" onclick="applyFilters()"> | |
<i class="fas fa-filter"></i> | |
اعمال فیلتر | |
</button> | |
</div> | |
</section> | |
<!-- متریکهای زنده --> | |
<section class="live-metrics"> | |
<div class="live-metric"> | |
<div class="live-indicator"></div> | |
<div class="live-value" id="liveUsers">12</div> | |
<div class="live-label">کاربران آنلاین</div> | |
</div> | |
<div class="live-metric"> | |
<div class="live-indicator"></div> | |
<div class="live-value" id="liveProcessing">3</div> | |
<div class="live-label">در حال پردازش</div> | |
</div> | |
<div class="live-metric"> | |
<div class="live-indicator"></div> | |
<div class="live-value" id="liveRequests">847</div> | |
<div class="live-label">درخواستهای امروز</div> | |
</div> | |
<div class="live-metric"> | |
<div class="live-indicator"></div> | |
<div class="live-value" id="liveSuccess">98.7%</div> | |
<div class="live-label">نرخ موفقیت</div> | |
</div> | |
</section> | |
<!-- آمار کلی --> | |
<section class="overview-stats"> | |
<div class="stat-card primary"> | |
<div class="stat-value" id="totalDocumentsAnalytics">156</div> | |
<div class="stat-label">کل اسناد پردازش شده</div> | |
<div class="stat-change positive"> | |
<i class="fas fa-arrow-up"></i> | |
<span>+15.2%</span> | |
</div> | |
</div> | |
<div class="stat-card success"> | |
<div class="stat-value" id="successfulProcessing">142</div> | |
<div class="stat-label">پردازش موفق</div> | |
<div class="stat-change positive"> | |
<i class="fas fa-arrow-up"></i> | |
<span>+23.1%</span> | |
</div> | |
</div> | |
<div class="stat-card warning"> | |
<div class="stat-value" id="averageTime">2.4s</div> | |
<div class="stat-label">میانگین زمان پردازش</div> | |
<div class="stat-change negative"> | |
<i class="fas fa-arrow-down"></i> | |
<span>-8.3%</span> | |
</div> | |
</div> | |
<div class="stat-card danger"> | |
<div class="stat-value" id="errorRate">1.3%</div> | |
<div class="stat-label">نرخ خطا</div> | |
<div class="stat-change positive"> | |
<i class="fas fa-arrow-down"></i> | |
<span>-12.7%</span> | |
</div> | |
</div> | |
</section> | |
<!-- تحلیلهای اصلی --> | |
<section class="main-analytics"> | |
<div class="main-grid"> | |
<div class="analytics-card"> | |
<div class="analytics-header"> | |
<h3 class="analytics-title"> | |
<i class="fas fa-chart-line"></i> | |
روند پردازش اسناد | |
</h3> | |
<div class="chart-filters"> | |
<button type="button" class="chart-filter" onclick="updateTrendsChart('daily')">روزانه</button> | |
<button type="button" class="chart-filter active" onclick="updateTrendsChart('weekly')">هفتگی</button> | |
<button type="button" class="chart-filter" onclick="updateTrendsChart('monthly')">ماهانه</button> | |
</div> | |
</div> | |
<div class="chart-container"> | |
<canvas id="trendsChart"></canvas> | |
</div> | |
</div> | |
<div class="analytics-card"> | |
<div class="analytics-header"> | |
<h3 class="analytics-title"> | |
<i class="fas fa-chart-pie"></i> | |
توزیع دستهبندی | |
</h3> | |
<div class="analytics-actions"> | |
<button type="button" class="btn btn-outline btn-sm" onclick="refreshCategoryChart()"> | |
<i class="fas fa-sync-alt"></i> | |
</button> | |
</div> | |
</div> | |
<div class="chart-container"> | |
<canvas id="categoryChart"></canvas> | |
</div> | |
</div> | |
</div> | |
</section> | |
<!-- ویجتهای پیشرفته --> | |
<section class="advanced-widgets"> | |
<div class="widget"> | |
<div class="widget-header"> | |
<h3 class="widget-title">عملکرد کیفیت</h3> | |
<button type="button" class="btn btn-outline btn-sm" onclick="refreshQualityWidget()"> | |
<i class="fas fa-sync-alt"></i> | |
</button> | |
</div> | |
<div class="progress-widget"> | |
<div class="progress-item"> | |
<div class="progress-info"> | |
<div class="progress-label">دقت OCR</div> | |
<div class="progress-bar"> | |
<div class="progress-fill success" style="width: 94%"></div> | |
</div> | |
</div> | |
<div class="progress-value">94%</div> | |
</div> | |
<div class="progress-item"> | |
<div class="progress-info"> | |
<div class="progress-label">کیفیت تصویر</div> | |
<div class="progress-bar"> | |
<div class="progress-fill primary" style="width: 87%"></div> | |
</div> | |
</div> | |
<div class="progress-value">87%</div> | |
</div> | |
<div class="progress-item"> | |
<div class="progress-info"> | |
<div class="progress-label">تطبیق فرمت</div> | |
<div class="progress-bar"> | |
<div class="progress-fill warning" style="width: 76%"></div> | |
</div> | |
</div> | |
<div class="progress-value">76%</div> | |
</div> | |
<div class="progress-item"> | |
<div class="progress-info"> | |
<div class="progress-label">کامل بودن محتوا</div> | |
<div class="progress-bar"> | |
<div class="progress-fill danger" style="width: 68%"></div> | |
</div> | |
</div> | |
<div class="progress-value">68%</div> | |
</div> | |
</div> | |
</div> | |
<div class="widget"> | |
<div class="widget-header"> | |
<h3 class="widget-title">آمار سیستم</h3> | |
<button type="button" class="btn btn-outline btn-sm" onclick="refreshSystemStats()"> | |
<i class="fas fa-sync-alt"></i> | |
</button> | |
</div> | |
<div class="chart-container"> | |
<canvas id="systemChart"></canvas> | |
</div> | |
</div> | |
</section> | |
<!-- گرید تحلیلهای تفصیلی --> | |
<section class="analytics-grid"> | |
<div class="analytics-card"> | |
<div class="analytics-header"> | |
<h3 class="analytics-title"> | |
<i class="fas fa-users"></i> | |
فعالیت کاربران | |
</h3> | |
<div class="analytics-actions"> | |
<button type="button" class="btn btn-outline btn-sm" onclick="refreshUserActivity()"> | |
<i class="fas fa-sync-alt"></i> | |
</button> | |
</div> | |
</div> | |
<div class="chart-container"> | |
<canvas id="userActivityChart"></canvas> | |
</div> | |
</div> | |
<div class="analytics-card"> | |
<div class="analytics-header"> | |
<h3 class="analytics-title"> | |
<i class="fas fa-clock"></i> | |
زمان پاسخدهی | |
</h3> | |
<div class="analytics-actions"> | |
<button type="button" class="btn btn-outline btn-sm" onclick="refreshResponseTime()"> | |
<i class="fas fa-sync-alt"></i> | |
</button> | |
</div> | |
</div> | |
<div class="chart-container"> | |
<canvas id="responseTimeChart"></canvas> | |
</div> | |
</div> | |
<div class="analytics-card"> | |
<div class="analytics-header"> | |
<h3 class="analytics-title"> | |
<i class="fas fa-chart-bar"></i> | |
مقایسه کارایی | |
</h3> | |
<div class="chart-filters"> | |
<button type="button" class="chart-filter active" onclick="updatePerformanceChart('hourly')">ساعتی</button> | |
<button type="button" class="chart-filter" onclick="updatePerformanceChart('daily')">روزانه</button> | |
</div> | |
</div> | |
<div class="chart-container"> | |
<canvas id="performanceChart"></canvas> | |
</div> | |
</div> | |
<div class="analytics-card"> | |
<div class="analytics-header"> | |
<h3 class="analytics-title"> | |
<i class="fas fa-exclamation-triangle"></i> | |
تحلیل خطاها | |
</h3> | |
<div class="analytics-actions"> | |
<button type="button" class="btn btn-outline btn-sm" onclick="refreshErrorAnalysis()"> | |
<i class="fas fa-sync-alt"></i> | |
</button> | |
</div> | |
</div> | |
<table class="stats-table"> | |
<thead> | |
<tr> | |
<th>نوع خطا</th> | |
<th>تعداد</th> | |
<th>درصد</th> | |
</tr> | |
</thead> | |
<tbody id="errorAnalysisTable"> | |
<tr> | |
<td>خطای شبکه</td> | |
<td>12</td> | |
<td>45%</td> | |
</tr> | |
<tr> | |
<td>خطای پردازش</td> | |
<td>8</td> | |
<td>30%</td> | |
</tr> | |
<tr> | |
<td>خطای فرمت</td> | |
<td>4</td> | |
<td>15%</td> | |
</tr> | |
<tr> | |
<td>خطای اعتبارسنجی</td> | |
<td>3</td> | |
<td>10%</td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
</section> | |
</main> | |
</div> | |
<!-- Toast Container --> | |
<div class="toast-container" id="toastContainer"></div> | |
<script> | |
// Global variables | |
let chartsInstances = {}; | |
let liveMetricsInterval; | |
let isOnline = false; | |
// Initialize page | |
document.addEventListener('DOMContentLoaded', function() { | |
console.log('📊 Analytics page loading...'); | |
initializeAnalyticsPage(); | |
}); | |
async function initializeAnalyticsPage() { | |
try { | |
// Test backend connection | |
isOnline = await testConnection(); | |
// Initialize date filters | |
initializeDateFilters(); | |
// Initialize charts | |
initializeCharts(); | |
// Start live metrics updates | |
startLiveMetrics(); | |
showToast('داشبورد تحلیلی آماده است', 'success', 'آماده'); | |
} catch (error) { | |
console.error('Failed to initialize analytics page:', error); | |
// Fallback mode | |
isOnline = false; | |
initializeDateFilters(); | |
initializeCharts(); | |
startLiveMetrics(); | |
showToast('حالت آفلاین فعال است', 'warning', 'اتصال ناموفق'); | |
} | |
} | |
async function testConnection() { | |
try { | |
await window.legalAPI.healthCheck(); | |
return true; | |
} catch (error) { | |
return false; | |
} | |
} | |
function initializeDateFilters() { | |
const endDate = new Date(); | |
const startDate = new Date(); | |
startDate.setDate(startDate.getDate() - 7); // Last week | |
document.getElementById('endDate').value = endDate.toISOString().split('T')[0]; | |
document.getElementById('startDate').value = startDate.toISOString().split('T')[0]; | |
} | |
function initializeCharts() { | |
try { | |
// Initialize all charts | |
createTrendsChart(); | |
createCategoryChart(); | |
createSystemChart(); | |
createUserActivityChart(); | |
createResponseTimeChart(); | |
createPerformanceChart(); | |
console.log('✅ All charts initialized'); | |
} catch (error) { | |
console.error('Failed to initialize charts:', error); | |
showToast('خطا در بارگذاری نمودارها', 'error', 'خطا'); | |
} | |
} | |
function createTrendsChart() { | |
const ctx = document.getElementById('trendsChart'); | |
if (!ctx) return; | |
chartsInstances.trends = new Chart(ctx, { | |
type: 'line', | |
data: { | |
labels: ['شنبه', 'یکشنبه', 'دوشنبه', 'سهشنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'], | |
datasets: [ | |
{ | |
label: 'اسناد پردازش شده', | |
data: [12, 19, 8, 15, 22, 18, 14], | |
borderColor: '#3b82f6', | |
backgroundColor: 'rgba(59, 130, 246, 0.1)', | |
tension: 0.4, | |
borderWidth: 3, | |
pointRadius: 6, | |
pointHoverRadius: 8 | |
}, | |
{ | |
label: 'اسناد آپلود شده', | |
data: [15, 23, 12, 18, 25, 21, 16], | |
borderColor: '#10b981', | |
backgroundColor: 'rgba(16, 185, 129, 0.1)', | |
tension: 0.4, | |
borderWidth: 3, | |
pointRadius: 6, | |
pointHoverRadius: 8 | |
} | |
] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
plugins: { | |
legend: { | |
position: 'top', | |
labels: { | |
usePointStyle: true, | |
font: { family: 'Vazirmatn', size: 12 } | |
} | |
} | |
}, | |
scales: { | |
y: { | |
beginAtZero: true, | |
grid: { color: 'rgba(0, 0, 0, 0.05)' }, | |
ticks: { font: { family: 'Vazirmatn' } } | |
}, | |
x: { | |
grid: { color: 'rgba(0, 0, 0, 0.05)' }, | |
ticks: { font: { family: 'Vazirmatn' } } | |
} | |
} | |
} | |
}); | |
} | |
function createCategoryChart() { | |
const ctx = document.getElementById('categoryChart'); | |
if (!ctx) return; | |
chartsInstances.category = new Chart(ctx, { | |
type: 'doughnut', | |
data: { | |
labels: ['قراردادها', 'دادخواستها', 'احکام قضایی', 'آرای دیوان', 'سایر'], | |
datasets: [{ | |
data: [35, 25, 20, 15, 5], | |
backgroundColor: [ | |
'#3b82f6', | |
'#10b981', | |
'#f59e0b', | |
'#ef4444', | |
'#8b5cf6' | |
], | |
borderColor: '#ffffff', | |
borderWidth: 3, | |
hoverBorderWidth: 5 | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
plugins: { | |
legend: { | |
position: 'bottom', | |
labels: { | |
usePointStyle: true, | |
padding: 15, | |
font: { family: 'Vazirmatn', size: 11 } | |
} | |
} | |
}, | |
cutout: '60%' | |
} | |
}); | |
} | |
function createSystemChart() { | |
const ctx = document.getElementById('systemChart'); | |
if (!ctx) return; | |
chartsInstances.system = new Chart(ctx, { | |
type: 'bar', | |
data: { | |
labels: ['CPU', 'RAM', 'دیسک', 'شبکه'], | |
datasets: [{ | |
label: 'درصد استفاده', | |
data: [45, 62, 38, 28], | |
backgroundColor: [ | |
'rgba(59, 130, 246, 0.8)', | |
'rgba(16, 185, 129, 0.8)', | |
'rgba(245, 158, 11, 0.8)', | |
'rgba(239, 68, 68, 0.8)' | |
], | |
borderColor: [ | |
'#3b82f6', | |
'#10b981', | |
'#f59e0b', | |
'#ef4444' | |
], | |
borderWidth: 2 | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
scales: { | |
y: { | |
beginAtZero: true, | |
max: 100, | |
ticks: { | |
callback: function(value) { return value + '%'; }, | |
font: { family: 'Vazirmatn' } | |
} | |
}, | |
x: { | |
ticks: { font: { family: 'Vazirmatn' } } | |
} | |
}, | |
plugins: { | |
legend: { display: false } | |
} | |
} | |
}); | |
} | |
function createUserActivityChart() { | |
const ctx = document.getElementById('userActivityChart'); | |
if (!ctx) return; | |
chartsInstances.userActivity = new Chart(ctx, { | |
type: 'radar', | |
data: { | |
labels: ['صبح', 'ظهر', 'بعدازظهر', 'عصر', 'شب'], | |
datasets: [{ | |
label: 'فعالیت کاربران', | |
data: [65, 89, 80, 81, 45], | |
backgroundColor: 'rgba(59, 130, 246, 0.2)', | |
borderColor: '#3b82f6', | |
pointBackgroundColor: '#3b82f6', | |
pointBorderColor: '#ffffff', | |
pointHoverBackgroundColor: '#ffffff', | |
pointHoverBorderColor: '#3b82f6' | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
scales: { | |
r: { | |
beginAtZero: true, | |
max: 100, | |
ticks: { font: { family: 'Vazirmatn' } } | |
} | |
}, | |
plugins: { | |
legend: { display: false } | |
} | |
} | |
}); | |
} | |
function createResponseTimeChart() { | |
const ctx = document.getElementById('responseTimeChart'); | |
if (!ctx) return; | |
chartsInstances.responseTime = new Chart(ctx, { | |
type: 'line', | |
data: { | |
labels: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'], | |
datasets: [{ | |
label: 'زمان پاسخ (ms)', | |
data: [250, 180, 320, 280, 380, 220], | |
borderColor: '#f59e0b', | |
backgroundColor: 'rgba(245, 158, 11, 0.1)', | |
tension: 0.4, | |
borderWidth: 2, | |
pointRadius: 4 | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
scales: { | |
y: { | |
beginAtZero: true, | |
ticks: { | |
callback: function(value) { return value + 'ms'; }, | |
font: { family: 'Vazirmatn' } | |
} | |
}, | |
x: { | |
ticks: { font: { family: 'Vazirmatn' } } | |
} | |
}, | |
plugins: { | |
legend: { display: false } | |
} | |
} | |
}); | |
} | |
function createPerformanceChart() { | |
const ctx = document.getElementById('performanceChart'); | |
if (!ctx) return; | |
chartsInstances.performance = new Chart(ctx, { | |
type: 'bar', | |
data: { | |
labels: ['پردازش', 'آپلود', 'جستجو', 'تحلیل'], | |
datasets: [ | |
{ | |
label: 'این هفته', | |
data: [85, 92, 78, 88], | |
backgroundColor: 'rgba(59, 130, 246, 0.8)', | |
borderColor: '#3b82f6', | |
borderWidth: 1 | |
}, | |
{ | |
label: 'هفته گذشته', | |
data: [75, 85, 72, 82], | |
backgroundColor: 'rgba(16, 185, 129, 0.8)', | |
borderColor: '#10b981', | |
borderWidth: 1 | |
} | |
] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
scales: { | |
y: { | |
beginAtZero: true, | |
max: 100, | |
ticks: { | |
callback: function(value) { return value + '%'; }, | |
font: { family: 'Vazirmatn' } | |
} | |
}, | |
x: { | |
ticks: { font: { family: 'Vazirmatn' } } | |
} | |
}, | |
plugins: { | |
legend: { | |
position: 'top', | |
labels: { font: { family: 'Vazirmatn' } } | |
} | |
} | |
} | |
}); | |
} | |
// Live metrics updates | |
function startLiveMetrics() { | |
liveMetricsInterval = setInterval(updateLiveMetrics, 5000); // Update every 5 seconds | |
updateLiveMetrics(); // Initial update | |
} | |
function updateLiveMetrics() { | |
// Simulate live data updates | |
const liveUsers = Math.floor(Math.random() * 20) + 5; | |
const liveProcessing = Math.floor(Math.random() * 8) + 1; | |
const liveRequests = Math.floor(Math.random() * 100) + 800; | |
const liveSuccess = (Math.random() * 5 + 95).toFixed(1); | |
document.getElementById('liveUsers').textContent = liveUsers; | |
document.getElementById('liveProcessing').textContent = liveProcessing; | |
document.getElementById('liveRequests').textContent = liveRequests; | |
document.getElementById('liveSuccess').textContent = liveSuccess + '%'; | |
} | |
// Chart update functions | |
function updateTrendsChart(period) { | |
// Update active filter | |
document.querySelectorAll('.chart-filter').forEach(btn => { | |
btn.classList.remove('active'); | |
}); | |
event.target.classList.add('active'); | |
// Update chart data based on period | |
const data = { | |
daily: { | |
labels: ['شنبه', 'یکشنبه', 'دوشنبه', 'سهشنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'], | |
processed: [12, 19, 8, 15, 22, 18, 14], | |
uploaded: [15, 23, 12, 18, 25, 21, 16] | |
}, | |
weekly: { | |
labels: ['هفته 1', 'هفته 2', 'هفته 3', 'هفته 4'], | |
processed: [85, 92, 78, 95], | |
uploaded: [95, 105, 88, 110] | |
}, | |
monthly: { | |
labels: ['فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور'], | |
processed: [340, 380, 290, 420, 380, 450], | |
uploaded: [380, 420, 320, 460, 410, 490] | |
} | |
}; | |
const selectedData = data[period] || data.weekly; | |
if (chartsInstances.trends) { | |
chartsInstances.trends.data.labels = selectedData.labels; | |
chartsInstances.trends.data.datasets[0].data = selectedData.processed; | |
chartsInstances.trends.data.datasets[1].data = selectedData.uploaded; | |
chartsInstances.trends.update('active'); | |
} | |
showToast(`نمودار به حالت ${period} تغییر کرد`, 'info', 'بروزرسانی'); | |
} | |
function updatePerformanceChart(type) { | |
// Update active filter | |
const parent = event.target.closest('.analytics-card'); | |
parent.querySelectorAll('.chart-filter').forEach(btn => { | |
btn.classList.remove('active'); | |
}); | |
event.target.classList.add('active'); | |
// Update chart based on type | |
const data = { | |
hourly: { | |
labels: ['پردازش', 'آپلود', 'جستجو', 'تحلیل'], | |
thisWeek: [85, 92, 78, 88], | |
lastWeek: [75, 85, 72, 82] | |
}, | |
daily: { | |
labels: ['شنبه', 'یکشنبه', 'دوشنبه', 'سهشنبه'], | |
thisWeek: [320, 450, 280, 380], | |
lastWeek: [280, 420, 250, 350] | |
} | |
}; | |
const selectedData = data[type] || data.hourly; | |
if (chartsInstances.performance) { | |
chartsInstances.performance.data.labels = selectedData.labels; | |
chartsInstances.performance.data.datasets[0].data = selectedData.thisWeek; | |
chartsInstances.performance.data.datasets[1].data = selectedData.lastWeek; | |
chartsInstances.performance.update('active'); | |
} | |
} | |
// Filter functions | |
function updateTimeRange() { | |
const timeRange = document.getElementById('timeRange').value; | |
const startDate = document.getElementById('startDate'); | |
const endDate = document.getElementById('endDate'); | |
const end = new Date(); | |
let start = new Date(); | |
switch (timeRange) { | |
case 'today': | |
start = new Date(); | |
break; | |
case 'week': | |
start.setDate(start.getDate() - 7); | |
break; | |
case 'month': | |
start.setMonth(start.getMonth() - 1); | |
break; | |
case 'quarter': | |
start.setMonth(start.getMonth() - 3); | |
break; | |
case 'year': | |
start.setFullYear(start.getFullYear() - 1); | |
break; | |
case 'custom': | |
return; // Don't update dates for custom range | |
} | |
startDate.value = start.toISOString().split('T')[0]; | |
endDate.value = end.toISOString().split('T')[0]; | |
applyFilters(); | |
} | |
function updateDataType() { | |
applyFilters(); | |
} | |
function applyFilters() { | |
const timeRange = document.getElementById('timeRange').value; | |
const dataType = document.getElementById('dataType').value; | |
const startDate = document.getElementById('startDate').value; | |
const endDate = document.getElementById('endDate').value; | |
showToast('فیلترها اعمال شدند و دادهها بروزرسانی شدند', 'success', 'فیلترها'); | |
// Here you would typically reload data based on filters | |
refreshAllAnalytics(); | |
} | |
// Refresh functions | |
function refreshAllAnalytics() { | |
showToast('در حال بروزرسانی همه تحلیلها...', 'info', 'بروزرسانی'); | |
// Simulate data refresh | |
setTimeout(() => { | |
updateLiveMetrics(); | |
// Update some chart data randomly | |
if (chartsInstances.trends) { | |
const newData = chartsInstances.trends.data.datasets[0].data.map(() => | |
Math.floor(Math.random() * 30) + 10 | |
); | |
chartsInstances.trends.data.datasets[0].data = newData; | |
chartsInstances.trends.update('active'); | |
} | |
showToast('همه تحلیلها بروزرسانی شدند', 'success', 'بروزرسانی موفق'); | |
}, 2000); | |
} | |
function refreshCategoryChart() { | |
if (chartsInstances.category) { | |
const newData = [ | |
Math.floor(Math.random() * 40) + 20, | |
Math.floor(Math.random() * 30) + 15, | |
Math.floor(Math.random() * 25) + 10, | |
Math.floor(Math.random() * 20) + 5, | |
Math.floor(Math.random() * 15) + 5 | |
]; | |
chartsInstances.category.data.datasets[0].data = newData; | |
chartsInstances.category.update('active'); | |
} | |
showToast('نمودار دستهبندی بروزرسانی شد', 'success', 'بروزرسانی'); | |
} | |
function refreshQualityWidget() { | |
// Update progress bars with random values | |
const progressBars = document.querySelectorAll('.progress-fill'); | |
const progressValues = document.querySelectorAll('.progress-value'); | |
progressBars.forEach((bar, index) => { | |
const newValue = Math.floor(Math.random() * 30) + 60; | |
bar.style.width = newValue + '%'; | |
progressValues[index].textContent = newValue + '%'; | |
}); | |
showToast('ویجت کیفیت بروزرسانی شد', 'success', 'بروزرسانی'); | |
} | |
function refreshSystemStats() { | |
if (chartsInstances.system) { | |
const newData = [ | |
Math.floor(Math.random() * 40) + 30, | |
Math.floor(Math.random() * 50) + 40, | |
Math.floor(Math.random() * 30) + 20, | |
Math.floor(Math.random() * 40) + 15 | |
]; | |
chartsInstances.system.data.datasets[0].data = newData; | |
chartsInstances.system.update('active'); | |
} | |
showToast('آمار سیستم بروزرسانی شد', 'success', 'بروزرسانی'); | |
} | |
function refreshUserActivity() { | |
if (chartsInstances.userActivity) { | |
const newData = Array.from({length: 5}, () => Math.floor(Math.random() * 50) + 40); | |
chartsInstances.userActivity.data.datasets[0].data = newData; | |
chartsInstances.userActivity.update('active'); | |
} | |
showToast('فعالیت کاربران بروزرسانی شد', 'success', 'بروزرسانی'); | |
} | |
function refreshResponseTime() { | |
if (chartsInstances.responseTime) { | |
const newData = Array.from({length: 6}, () => Math.floor(Math.random() * 200) + 150); | |
chartsInstances.responseTime.data.datasets[0].data = newData; | |
chartsInstances.responseTime.update('active'); | |
} | |
showToast('زمان پاسخدهی بروزرسانی شد', 'success', 'بروزرسانی'); | |
} | |
function refreshErrorAnalysis() { | |
// Update error analysis table with random data | |
const tbody = document.getElementById('errorAnalysisTable'); | |
const rows = tbody.querySelectorAll('tr'); | |
rows.forEach(row => { | |
const cells = row.querySelectorAll('td'); | |
if (cells.length >= 3) { | |
const newCount = Math.floor(Math.random() * 15) + 3; | |
const newPercent = Math.floor(Math.random() * 40) + 10; | |
cells[1].textContent = newCount; | |
cells[2].textContent = newPercent + '%'; | |
} | |
}); | |
showToast('تحلیل خطاها بروزرسانی شد', 'success', 'بروزرسانی'); | |
} | |
function exportAnalytics() { | |
showToast('گزارش آمار در حال آمادهسازی...', 'info', 'خروجی'); | |
setTimeout(() => { | |
showToast('گزارش آمار آماده شد و دانلود شروع شد', 'success', 'خروجی موفق'); | |
}, 3000); | |
} | |
// Cleanup on page unload | |
window.addEventListener('beforeunload', function() { | |
if (liveMetricsInterval) { | |
clearInterval(liveMetricsInterval); | |
} | |
// Destroy all chart instances | |
Object.values(chartsInstances).forEach(chart => { | |
if (chart && chart.destroy) { | |
chart.destroy(); | |
} | |
}); | |
}); | |
function showToast(message, type = 'info', title = 'اعلان') { | |
const toastContainer = document.getElementById('toastContainer'); | |
if (!toastContainer) return; | |
const toast = document.createElement('div'); | |
toast.className = `toast ${type}`; | |
const icons = { | |
success: 'check-circle', | |
error: 'exclamation-triangle', | |
warning: 'exclamation-circle', | |
info: 'info-circle' | |
}; | |
toast.innerHTML = ` | |
<div class="toast-icon"> | |
<i class="fas fa-${icons[type]}"></i> | |
</div> | |
<div class="toast-content"> | |
<div class="toast-title">${title}</div> | |
<div class="toast-message">${message}</div> | |
</div> | |
<button type="button" class="toast-close" onclick="this.parentElement.remove()"> | |
<i class="fas fa-times"></i> | |
</button> | |
`; | |
toastContainer.appendChild(toast); | |
// Show toast | |
setTimeout(() => toast.classList.add('show'), 100); | |
// Auto remove after 5 seconds | |
setTimeout(() => { | |
if (toast.parentElement) { | |
toast.classList.remove('show'); | |
setTimeout(() => { | |
if (toast.parentElement) { | |
toast.remove(); | |
} | |
}, 300); | |
} | |
}, 5000); | |
} | |
console.log('📊 Analytics Page Ready!'); | |
</script> | |
</body> | |
</html> |