diff --git a/public/admin-stats.js b/public/admin-stats.js
index 5fda563..84d069d 100644
--- a/public/admin-stats.js
+++ b/public/admin-stats.js
@@ -68,11 +68,11 @@ function renderStatsSection() {
-
-
+
-
+
+
@@ -554,8 +554,6 @@ function renderStatsTable() {
${stat.userName || 'Не указано'}
- ${stat.userLogin || 'Нет логина'}
- ${stat.userEmail || 'Нет email'}
|
diff --git a/public/admin.html b/public/admin.html
index f333f00..2506525 100644
--- a/public/admin.html
+++ b/public/admin.html
@@ -5,273 +5,6 @@
School CRM - Административная панель
-
diff --git a/public/style.css b/public/style.css
index 2378b86..d0ab722 100644
--- a/public/style.css
+++ b/public/style.css
@@ -3846,4 +3846,269 @@ button.btn-primary {
max-width: 600px; /* Максимальная ширина */
padding: 14px 20px; /* Увеличиваем внутренние отступы */
font-size: 1.1rem; /* Увеличиваем шрифт */
-}
\ No newline at end of file
+}
+ /* Дополнительные стили для детальной статистики */
+ .filters-container {
+ background: #fff;
+ padding: 20px;
+ border-radius: 8px;
+ margin-bottom: 20px;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ }
+
+ .filter-row {
+ display: flex;
+ gap: 20px;
+ margin-bottom: 15px;
+ flex-wrap: wrap;
+ }
+
+ .filter-group {
+ flex: 1;
+ min-width: 200px;
+ }
+
+ .filter-group label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: 600;
+ color: #333;
+ }
+
+ .filter-group select {
+ width: 100%;
+ padding: 8px 12px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 14px;
+ }
+
+ .filter-actions {
+ display: flex;
+ gap: 10px;
+ margin-top: 10px;
+ }
+
+ .users-stats-table {
+ width: 100%;
+ border-collapse: collapse;
+ background: #fff;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
+ .users-stats-table th {
+ background: #f8f9fa;
+ padding: 12px 15px;
+ text-align: left;
+ font-weight: 600;
+ color: #333;
+ border-bottom: 2px solid #dee2e6;
+ }
+
+ .users-stats-table td {
+ padding: 12px 15px;
+ border-bottom: 1px solid #dee2e6;
+ }
+
+ .users-stats-table tr:hover {
+ background: #f8f9fa;
+ }
+
+ .statuses-container {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ }
+
+ .status-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .status-badge {
+ display: inline-block;
+ padding: 3px 8px;
+ border-radius: 12px;
+ font-size: 12px;
+ font-weight: 600;
+ }
+
+ .status-assigned { background: #e3f2fd; color: #1976d2; }
+ .status-in-progress { background: #fff3e0; color: #f57c00; }
+ .status-completed { background: #e8f5e9; color: #388e3c; }
+ .status-overdue { background: #ffebee; color: #d32f2f; }
+ .status-rework { background: #f3e5f5; color: #7b1fa2; }
+
+ .status-count {
+ font-weight: 600;
+ min-width: 20px;
+ text-align: right;
+ }
+
+ .no-statuses {
+ color: #999;
+ font-style: italic;
+ font-size: 12px;
+ }
+
+ .user-role {
+ display: inline-block;
+ padding: 3px 8px;
+ border-radius: 12px;
+ font-size: 12px;
+ font-weight: 600;
+ background: #f5f5f5;
+ color: #666;
+ }
+
+ .user-role.admin { background: #ffebee; color: #d32f2f; }
+ .user-role.teacher { background: #e3f2fd; color: #1976d2; }
+
+ .stat-numbers {
+ display: flex;
+ gap: 10px;
+ margin-top: 5px;
+ }
+
+ .stat-number {
+ background: #f8f9fa;
+ padding: 4px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+ }
+
+ .export-btn {
+ background: #28a745;
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-weight: 600;
+ }
+
+ .export-btn:hover {
+ background: #218838;
+ }
+
+ .reset-btn {
+ background: #1976d2;
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ }
+
+ .reset-btn:hover {
+ background: #e00707;
+ }
+
+ .no-data {
+ text-align: center;
+ padding: 40px;
+ color: #666;
+ font-style: italic;
+ }
+
+ .stats-loading {
+ text-align: center;
+ padding: 40px;
+ color: #666;
+ }
+
+ .stats-error {
+ text-align: center;
+ padding: 40px;
+ color: #dc3545;
+ }
+
+ .pagination {
+ display: flex;
+ justify-content: center;
+ gap: 10px;
+ margin-top: 20px;
+ }
+
+ .page-btn {
+ padding: 6px 12px;
+ border: 1px solid #ddd;
+ background: white;
+ border-radius: 4px;
+ cursor: pointer;
+ }
+
+ .page-btn.active {
+ background: #007bff;
+ color: white;
+ border-color: #007bff;
+ }
+
+ .page-btn:hover:not(.active) {
+ background: #f8f9fa;
+ }
+
+ .page-btn:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+
+ .stats-summary {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+ }
+
+ .total-count {
+ font-weight: 600;
+ color: #333;
+ }
+
+ .page-dots {
+ padding: 6px 12px;
+ color: #666;
+ }
+
+ .user-info {
+ line-height: 1.4;
+ }
+
+ .user-login {
+ font-size: 12px;
+ color: #666;
+ }
+
+ .user-email {
+ font-size: 12px;
+ color: #999;
+ }
+
+ .stats-header {
+ margin-bottom: 20px;
+ }
+
+ .stats-header h2 {
+ margin-bottom: 5px;
+ }
+
+ .stats-header p {
+ color: #666;
+ margin: 0;
+ }
+
+ .overall-stats {
+ margin-bottom: 30px;
+ }
+
+ .overall-stats h3 {
+ margin-bottom: 15px;
+ }
+
+ .detailed-stats h3 {
+ margin-bottom: 15px;
+ }
\ No newline at end of file
diff --git a/public/ui.js b/public/ui.js
index 8127be5..1486aec 100644
--- a/public/ui.js
+++ b/public/ui.js
@@ -80,15 +80,16 @@ function renderTasks() {
+ ${isExpanded ? `
${!isDeleted && !isClosed ? `
-${currentUser && currentUser.login === 'kalugin.o' ? `` : ''}
-${currentUser && currentUser.login === 'kalugin.o' ? `` : ''}
+ ${currentUser && currentUser.login === 'minicrm' ? `` : ''}
+ ${currentUser && currentUser.login === 'minicrm' ? `` : ''}
- ${canEdit ? `` : ''}
- ${canEdit ? `` : ''}
+ ${currentUser && currentUser.login === 'minicrm' ? `` : ''}
+ ${currentUser && currentUser.login === 'minicrm' ? `` : ''}
${canEdit ? `` : ''}
` : ''}
${isClosed && canEdit ? `
@@ -98,6 +99,7 @@ ${currentUser && currentUser.login === 'kalugin.o' ? `
` : ''}
+ ` : ''}
${isCopy && task.original_task_title ? `
@@ -139,7 +141,6 @@ ${task.assignments && task.assignments.length > 0 ?
${task.deleted_at ? ` Удалена: ${formatDateTime(task.deleted_at)}` : ''}
${task.closed_at ? ` Закрыта: ${formatDateTime(task.closed_at)}` : ''}
-
`;
}).join('');
diff --git a/server.js b/server.js
index 83d5ce4..c6e096a 100644
--- a/server.js
+++ b/server.js
@@ -694,6 +694,9 @@ app.get('/api/postgres-health', requireAuth, async (req, res) => {
// Админ панель
app.get('/admin', (req, res) => {
+ if (!req.session.user) {
+ return res.redirect('/');
+ }
if (!req.session.user || req.session.user.role !== 'admin') {
return res.status(403).send('Доступ запрещен');
}
@@ -702,6 +705,9 @@ app.get('/admin', (req, res) => {
// Страница профилей пользователей (только для админов)
app.get('/admin/profiles', (req, res) => {
+ if (!req.session.user) {
+ return res.redirect('/');
+ }
if (!req.session.user || req.session.user.role !== 'admin') {
return res.status(403).send('Доступ запрещен');
}
|