Add detailed statistics API v2 documentation and implement frontend components for displaying statistics

This commit is contained in:
Primakov Alexandr Alexandrovich
2025-11-04 21:37:03 +03:00
parent b91ee56bf0
commit fd55d5a214
16 changed files with 2233 additions and 29 deletions

View File

@@ -11,7 +11,8 @@ stubs/api/
│ ├── chains.json # Цепочки (3 шт.)
│ ├── users.json # Пользователи (8 шт.)
│ ├── submissions.json # Попытки (8 шт.)
── stats.json # Системная статистика
── stats.json # Системная статистика (v1)
│ └── stats-v2.json # Детальная статистика (v2, 20 заданий)
├── index.js # API роуты
└── README.md # Эта документация
```
@@ -36,7 +37,8 @@ stubs/api/
- `GET /api/challenge/users` - список всех пользователей
### Statistics (Статистика)
- `GET /api/challenge/stats` - общая системная статистика
- `GET /api/challenge/stats` - общая системная статистика (v1)
- `GET /api/challenge/stats/v2` - детальная статистика с таблицами и прогрессом (v2)
- `GET /api/challenge/user/:userId/stats` - статистика пользователя (генерируется динамически)
### Submissions (Попытки)
@@ -150,6 +152,17 @@ GET /api/challenge/user/user001/stats
Ответ будет содержать динамически вычисленную статистику на основе всех попыток пользователя.
### Получить детальную статистику (v2)
```bash
GET /api/challenge/stats/v2
```
Ответ будет содержать:
- Базовую статистику (users, tasks, chains, submissions, queue)
- Таблицу заданий с детальной статистикой (20 заданий с попытками, успешностью, средними показателями)
- 6 активных участников с прогрессом по цепочкам
- Детальную матрицу прогресса по каждой из 2 цепочек (Backend разработка - 10 заданий, Frontend разработка - 10 заданий)
## ⚙️ Настройка задержки
По умолчанию все запросы имеют задержку 300ms для имитации сетевых запросов. Изменить можно в `index.js`:

View File

@@ -0,0 +1,592 @@
{
"users": 8,
"tasks": 20,
"chains": 2,
"submissions": {
"total": 95,
"accepted": 38,
"rejected": 42,
"pending": 8,
"inProgress": 7
},
"averageCheckTimeMs": 2143,
"queue": {
"queueLength": 15,
"waiting": 8,
"inProgress": 7,
"maxConcurrency": 10,
"currentlyProcessing": 7
},
"tasksTable": [
{
"taskId": "task_1",
"title": "Создание REST API",
"totalAttempts": 12,
"uniqueUsers": 6,
"acceptedCount": 5,
"successRate": 83,
"averageAttemptsToSuccess": 2.4
},
{
"taskId": "task_2",
"title": "Работа с базой данных MongoDB",
"totalAttempts": 10,
"uniqueUsers": 5,
"acceptedCount": 3,
"successRate": 60,
"averageAttemptsToSuccess": 3.3
},
{
"taskId": "task_3",
"title": "JWT аутентификация",
"totalAttempts": 8,
"uniqueUsers": 4,
"acceptedCount": 2,
"successRate": 50,
"averageAttemptsToSuccess": 4.0
},
{
"taskId": "task_4",
"title": "Middleware для Express",
"totalAttempts": 6,
"uniqueUsers": 4,
"acceptedCount": 3,
"successRate": 75,
"averageAttemptsToSuccess": 2.0
},
{
"taskId": "task_5",
"title": "WebSocket сервер",
"totalAttempts": 5,
"uniqueUsers": 3,
"acceptedCount": 1,
"successRate": 33,
"averageAttemptsToSuccess": 5.0
},
{
"taskId": "task_6",
"title": "Кэширование с Redis",
"totalAttempts": 7,
"uniqueUsers": 4,
"acceptedCount": 2,
"successRate": 57,
"averageAttemptsToSuccess": 3.5
},
{
"taskId": "task_7",
"title": "GraphQL Schema",
"totalAttempts": 4,
"uniqueUsers": 3,
"acceptedCount": 2,
"successRate": 67,
"averageAttemptsToSuccess": 2.0
},
{
"taskId": "task_8",
"title": "Docker контейнеризация",
"totalAttempts": 3,
"uniqueUsers": 2,
"acceptedCount": 1,
"successRate": 50,
"averageAttemptsToSuccess": 3.0
},
{
"taskId": "task_9",
"title": "CI/CD Pipeline",
"totalAttempts": 2,
"uniqueUsers": 2,
"acceptedCount": 1,
"successRate": 50,
"averageAttemptsToSuccess": 2.0
},
{
"taskId": "task_10",
"title": "Микросервисная архитектура",
"totalAttempts": 2,
"uniqueUsers": 1,
"acceptedCount": 0,
"successRate": 0,
"averageAttemptsToSuccess": 0
},
{
"taskId": "task_11",
"title": "React компоненты",
"totalAttempts": 11,
"uniqueUsers": 6,
"acceptedCount": 6,
"successRate": 100,
"averageAttemptsToSuccess": 1.8
},
{
"taskId": "task_12",
"title": "React Hooks",
"totalAttempts": 9,
"uniqueUsers": 5,
"acceptedCount": 4,
"successRate": 80,
"averageAttemptsToSuccess": 2.3
},
{
"taskId": "task_13",
"title": "Redux State Management",
"totalAttempts": 7,
"uniqueUsers": 4,
"acceptedCount": 2,
"successRate": 57,
"averageAttemptsToSuccess": 3.5
},
{
"taskId": "task_14",
"title": "React Router",
"totalAttempts": 6,
"uniqueUsers": 4,
"acceptedCount": 3,
"successRate": 75,
"averageAttemptsToSuccess": 2.0
},
{
"taskId": "task_15",
"title": "Form валидация",
"totalAttempts": 5,
"uniqueUsers": 3,
"acceptedCount": 2,
"successRate": 67,
"averageAttemptsToSuccess": 2.5
},
{
"taskId": "task_16",
"title": "API интеграция",
"totalAttempts": 8,
"uniqueUsers": 5,
"acceptedCount": 3,
"successRate": 60,
"averageAttemptsToSuccess": 2.7
},
{
"taskId": "task_17",
"title": "CSS-in-JS стилизация",
"totalAttempts": 4,
"uniqueUsers": 3,
"acceptedCount": 2,
"successRate": 67,
"averageAttemptsToSuccess": 2.0
},
{
"taskId": "task_18",
"title": "Оптимизация производительности",
"totalAttempts": 3,
"uniqueUsers": 2,
"acceptedCount": 1,
"successRate": 50,
"averageAttemptsToSuccess": 3.0
},
{
"taskId": "task_19",
"title": "Unit тесты с Jest",
"totalAttempts": 2,
"uniqueUsers": 2,
"acceptedCount": 1,
"successRate": 50,
"averageAttemptsToSuccess": 2.0
},
{
"taskId": "task_20",
"title": "E2E тесты с Playwright",
"totalAttempts": 1,
"uniqueUsers": 1,
"acceptedCount": 0,
"successRate": 0,
"averageAttemptsToSuccess": 0
}
],
"activeParticipants": [
{
"userId": "user_1",
"nickname": "alex_dev",
"totalSubmissions": 18,
"completedTasks": 12,
"chainProgress": [
{
"chainId": "chain_1",
"chainName": "Backend разработка",
"totalTasks": 10,
"completedTasks": 6,
"progressPercent": 60
},
{
"chainId": "chain_2",
"chainName": "Frontend разработка",
"totalTasks": 10,
"completedTasks": 6,
"progressPercent": 60
}
]
},
{
"userId": "user_2",
"nickname": "maria_coder",
"totalSubmissions": 15,
"completedTasks": 9,
"chainProgress": [
{
"chainId": "chain_1",
"chainName": "Backend разработка",
"totalTasks": 10,
"completedTasks": 5,
"progressPercent": 50
},
{
"chainId": "chain_2",
"chainName": "Frontend разработка",
"totalTasks": 10,
"completedTasks": 4,
"progressPercent": 40
}
]
},
{
"userId": "user_3",
"nickname": "ivan_programmer",
"totalSubmissions": 10,
"completedTasks": 5,
"chainProgress": [
{
"chainId": "chain_1",
"chainName": "Backend разработка",
"totalTasks": 10,
"completedTasks": 3,
"progressPercent": 30
},
{
"chainId": "chain_2",
"chainName": "Frontend разработка",
"totalTasks": 10,
"completedTasks": 2,
"progressPercent": 20
}
]
},
{
"userId": "user_4",
"nickname": "kate_fullstack",
"totalSubmissions": 22,
"completedTasks": 15,
"chainProgress": [
{
"chainId": "chain_1",
"chainName": "Backend разработка",
"totalTasks": 10,
"completedTasks": 8,
"progressPercent": 80
},
{
"chainId": "chain_2",
"chainName": "Frontend разработка",
"totalTasks": 10,
"completedTasks": 7,
"progressPercent": 70
}
]
},
{
"userId": "user_5",
"nickname": "dmitry_backend",
"totalSubmissions": 12,
"completedTasks": 6,
"chainProgress": [
{
"chainId": "chain_1",
"chainName": "Backend разработка",
"totalTasks": 10,
"completedTasks": 5,
"progressPercent": 50
},
{
"chainId": "chain_2",
"chainName": "Frontend разработка",
"totalTasks": 10,
"completedTasks": 1,
"progressPercent": 10
}
]
},
{
"userId": "user_6",
"nickname": "anna_react",
"totalSubmissions": 14,
"completedTasks": 7,
"chainProgress": [
{
"chainId": "chain_1",
"chainName": "Backend разработка",
"totalTasks": 10,
"completedTasks": 1,
"progressPercent": 10
},
{
"chainId": "chain_2",
"chainName": "Frontend разработка",
"totalTasks": 10,
"completedTasks": 6,
"progressPercent": 60
}
]
}
],
"chainsDetailed": [
{
"chainId": "chain_1",
"name": "Backend разработка",
"totalTasks": 10,
"tasks": [
{ "taskId": "task_1", "title": "Создание REST API", "description": "Создайте REST API с Express.js" },
{ "taskId": "task_2", "title": "Работа с базой данных MongoDB", "description": "Интегрируйте MongoDB" },
{ "taskId": "task_3", "title": "JWT аутентификация", "description": "Реализуйте JWT-аутентификацию" },
{ "taskId": "task_4", "title": "Middleware для Express", "description": "Создайте кастомные middleware" },
{ "taskId": "task_5", "title": "WebSocket сервер", "description": "Реализуйте WebSocket для real-time" },
{ "taskId": "task_6", "title": "Кэширование с Redis", "description": "Внедрите Redis для кэширования" },
{ "taskId": "task_7", "title": "GraphQL Schema", "description": "Создайте GraphQL API" },
{ "taskId": "task_8", "title": "Docker контейнеризация", "description": "Контейнеризируйте приложение" },
{ "taskId": "task_9", "title": "CI/CD Pipeline", "description": "Настройте CI/CD" },
{ "taskId": "task_10", "title": "Микросервисная архитектура", "description": "Разбейте на микросервисы" }
],
"participantProgress": [
{
"userId": "user_1",
"nickname": "alex_dev",
"taskProgress": [
{ "taskId": "task_1", "taskTitle": "Создание REST API", "status": "completed" },
{ "taskId": "task_2", "taskTitle": "Работа с базой данных MongoDB", "status": "completed" },
{ "taskId": "task_3", "taskTitle": "JWT аутентификация", "status": "completed" },
{ "taskId": "task_4", "taskTitle": "Middleware для Express", "status": "completed" },
{ "taskId": "task_5", "taskTitle": "WebSocket сервер", "status": "completed" },
{ "taskId": "task_6", "taskTitle": "Кэширование с Redis", "status": "completed" },
{ "taskId": "task_7", "taskTitle": "GraphQL Schema", "status": "in_progress" },
{ "taskId": "task_8", "taskTitle": "Docker контейнеризация", "status": "not_started" },
{ "taskId": "task_9", "taskTitle": "CI/CD Pipeline", "status": "not_started" },
{ "taskId": "task_10", "taskTitle": "Микросервисная архитектура", "status": "not_started" }
],
"completedCount": 6,
"progressPercent": 60
},
{
"userId": "user_2",
"nickname": "maria_coder",
"taskProgress": [
{ "taskId": "task_1", "taskTitle": "Создание REST API", "status": "completed" },
{ "taskId": "task_2", "taskTitle": "Работа с базой данных MongoDB", "status": "completed" },
{ "taskId": "task_3", "taskTitle": "JWT аутентификация", "status": "completed" },
{ "taskId": "task_4", "taskTitle": "Middleware для Express", "status": "completed" },
{ "taskId": "task_5", "taskTitle": "WebSocket сервер", "status": "completed" },
{ "taskId": "task_6", "taskTitle": "Кэширование с Redis", "status": "needs_revision" },
{ "taskId": "task_7", "taskTitle": "GraphQL Schema", "status": "pending" },
{ "taskId": "task_8", "taskTitle": "Docker контейнеризация", "status": "not_started" },
{ "taskId": "task_9", "taskTitle": "CI/CD Pipeline", "status": "not_started" },
{ "taskId": "task_10", "taskTitle": "Микросервисная архитектура", "status": "not_started" }
],
"completedCount": 5,
"progressPercent": 50
},
{
"userId": "user_3",
"nickname": "ivan_programmer",
"taskProgress": [
{ "taskId": "task_1", "taskTitle": "Создание REST API", "status": "completed" },
{ "taskId": "task_2", "taskTitle": "Работа с базой данных MongoDB", "status": "completed" },
{ "taskId": "task_3", "taskTitle": "JWT аутентификация", "status": "completed" },
{ "taskId": "task_4", "taskTitle": "Middleware для Express", "status": "needs_revision" },
{ "taskId": "task_5", "taskTitle": "WebSocket сервер", "status": "not_started" },
{ "taskId": "task_6", "taskTitle": "Кэширование с Redis", "status": "not_started" },
{ "taskId": "task_7", "taskTitle": "GraphQL Schema", "status": "not_started" },
{ "taskId": "task_8", "taskTitle": "Docker контейнеризация", "status": "not_started" },
{ "taskId": "task_9", "taskTitle": "CI/CD Pipeline", "status": "not_started" },
{ "taskId": "task_10", "taskTitle": "Микросервисная архитектура", "status": "not_started" }
],
"completedCount": 3,
"progressPercent": 30
},
{
"userId": "user_4",
"nickname": "kate_fullstack",
"taskProgress": [
{ "taskId": "task_1", "taskTitle": "Создание REST API", "status": "completed" },
{ "taskId": "task_2", "taskTitle": "Работа с базой данных MongoDB", "status": "completed" },
{ "taskId": "task_3", "taskTitle": "JWT аутентификация", "status": "completed" },
{ "taskId": "task_4", "taskTitle": "Middleware для Express", "status": "completed" },
{ "taskId": "task_5", "taskTitle": "WebSocket сервер", "status": "completed" },
{ "taskId": "task_6", "taskTitle": "Кэширование с Redis", "status": "completed" },
{ "taskId": "task_7", "taskTitle": "GraphQL Schema", "status": "completed" },
{ "taskId": "task_8", "taskTitle": "Docker контейнеризация", "status": "completed" },
{ "taskId": "task_9", "taskTitle": "CI/CD Pipeline", "status": "in_progress" },
{ "taskId": "task_10", "taskTitle": "Микросервисная архитектура", "status": "not_started" }
],
"completedCount": 8,
"progressPercent": 80
},
{
"userId": "user_5",
"nickname": "dmitry_backend",
"taskProgress": [
{ "taskId": "task_1", "taskTitle": "Создание REST API", "status": "completed" },
{ "taskId": "task_2", "taskTitle": "Работа с базой данных MongoDB", "status": "completed" },
{ "taskId": "task_3", "taskTitle": "JWT аутентификация", "status": "completed" },
{ "taskId": "task_4", "taskTitle": "Middleware для Express", "status": "completed" },
{ "taskId": "task_5", "taskTitle": "WebSocket сервер", "status": "completed" },
{ "taskId": "task_6", "taskTitle": "Кэширование с Redis", "status": "in_progress" },
{ "taskId": "task_7", "taskTitle": "GraphQL Schema", "status": "not_started" },
{ "taskId": "task_8", "taskTitle": "Docker контейнеризация", "status": "not_started" },
{ "taskId": "task_9", "taskTitle": "CI/CD Pipeline", "status": "not_started" },
{ "taskId": "task_10", "taskTitle": "Микросервисная архитектура", "status": "not_started" }
],
"completedCount": 5,
"progressPercent": 50
},
{
"userId": "user_6",
"nickname": "anna_react",
"taskProgress": [
{ "taskId": "task_1", "taskTitle": "Создание REST API", "status": "completed" },
{ "taskId": "task_2", "taskTitle": "Работа с базой данных MongoDB", "status": "pending" },
{ "taskId": "task_3", "taskTitle": "JWT аутентификация", "status": "not_started" },
{ "taskId": "task_4", "taskTitle": "Middleware для Express", "status": "not_started" },
{ "taskId": "task_5", "taskTitle": "WebSocket сервер", "status": "not_started" },
{ "taskId": "task_6", "taskTitle": "Кэширование с Redis", "status": "not_started" },
{ "taskId": "task_7", "taskTitle": "GraphQL Schema", "status": "not_started" },
{ "taskId": "task_8", "taskTitle": "Docker контейнеризация", "status": "not_started" },
{ "taskId": "task_9", "taskTitle": "CI/CD Pipeline", "status": "not_started" },
{ "taskId": "task_10", "taskTitle": "Микросервисная архитектура", "status": "not_started" }
],
"completedCount": 1,
"progressPercent": 10
}
]
},
{
"chainId": "chain_2",
"name": "Frontend разработка",
"totalTasks": 10,
"tasks": [
{ "taskId": "task_11", "title": "React компоненты", "description": "Создайте переиспользуемые компоненты" },
{ "taskId": "task_12", "title": "React Hooks", "description": "Используйте хуки" },
{ "taskId": "task_13", "title": "Redux State Management", "description": "Управление состоянием" },
{ "taskId": "task_14", "title": "React Router", "description": "Маршрутизация" },
{ "taskId": "task_15", "title": "Form валидация", "description": "Валидация форм" },
{ "taskId": "task_16", "title": "API интеграция", "description": "Интеграция с API" },
{ "taskId": "task_17", "title": "CSS-in-JS стилизация", "description": "Стилизация" },
{ "taskId": "task_18", "title": "Оптимизация производительности", "description": "Оптимизация React" },
{ "taskId": "task_19", "title": "Unit тесты с Jest", "description": "Юнит тестирование" },
{ "taskId": "task_20", "title": "E2E тесты с Playwright", "description": "End-to-end тестирование" }
],
"participantProgress": [
{
"userId": "user_1",
"nickname": "alex_dev",
"taskProgress": [
{ "taskId": "task_11", "taskTitle": "React компоненты", "status": "completed" },
{ "taskId": "task_12", "taskTitle": "React Hooks", "status": "completed" },
{ "taskId": "task_13", "taskTitle": "Redux State Management", "status": "completed" },
{ "taskId": "task_14", "taskTitle": "React Router", "status": "completed" },
{ "taskId": "task_15", "taskTitle": "Form валидация", "status": "completed" },
{ "taskId": "task_16", "taskTitle": "API интеграция", "status": "completed" },
{ "taskId": "task_17", "taskTitle": "CSS-in-JS стилизация", "status": "in_progress" },
{ "taskId": "task_18", "taskTitle": "Оптимизация производительности", "status": "not_started" },
{ "taskId": "task_19", "taskTitle": "Unit тесты с Jest", "status": "not_started" },
{ "taskId": "task_20", "taskTitle": "E2E тесты с Playwright", "status": "not_started" }
],
"completedCount": 6,
"progressPercent": 60
},
{
"userId": "user_2",
"nickname": "maria_coder",
"taskProgress": [
{ "taskId": "task_11", "taskTitle": "React компоненты", "status": "completed" },
{ "taskId": "task_12", "taskTitle": "React Hooks", "status": "completed" },
{ "taskId": "task_13", "taskTitle": "Redux State Management", "status": "completed" },
{ "taskId": "task_14", "taskTitle": "React Router", "status": "completed" },
{ "taskId": "task_15", "taskTitle": "Form валидация", "status": "needs_revision" },
{ "taskId": "task_16", "taskTitle": "API интеграция", "status": "pending" },
{ "taskId": "task_17", "taskTitle": "CSS-in-JS стилизация", "status": "not_started" },
{ "taskId": "task_18", "taskTitle": "Оптимизация производительности", "status": "not_started" },
{ "taskId": "task_19", "taskTitle": "Unit тесты с Jest", "status": "not_started" },
{ "taskId": "task_20", "taskTitle": "E2E тесты с Playwright", "status": "not_started" }
],
"completedCount": 4,
"progressPercent": 40
},
{
"userId": "user_3",
"nickname": "ivan_programmer",
"taskProgress": [
{ "taskId": "task_11", "taskTitle": "React компоненты", "status": "completed" },
{ "taskId": "task_12", "taskTitle": "React Hooks", "status": "completed" },
{ "taskId": "task_13", "taskTitle": "Redux State Management", "status": "in_progress" },
{ "taskId": "task_14", "taskTitle": "React Router", "status": "not_started" },
{ "taskId": "task_15", "taskTitle": "Form валидация", "status": "not_started" },
{ "taskId": "task_16", "taskTitle": "API интеграция", "status": "not_started" },
{ "taskId": "task_17", "taskTitle": "CSS-in-JS стилизация", "status": "not_started" },
{ "taskId": "task_18", "taskTitle": "Оптимизация производительности", "status": "not_started" },
{ "taskId": "task_19", "taskTitle": "Unit тесты с Jest", "status": "not_started" },
{ "taskId": "task_20", "taskTitle": "E2E тесты с Playwright", "status": "not_started" }
],
"completedCount": 2,
"progressPercent": 20
},
{
"userId": "user_4",
"nickname": "kate_fullstack",
"taskProgress": [
{ "taskId": "task_11", "taskTitle": "React компоненты", "status": "completed" },
{ "taskId": "task_12", "taskTitle": "React Hooks", "status": "completed" },
{ "taskId": "task_13", "taskTitle": "Redux State Management", "status": "completed" },
{ "taskId": "task_14", "taskTitle": "React Router", "status": "completed" },
{ "taskId": "task_15", "taskTitle": "Form валидация", "status": "completed" },
{ "taskId": "task_16", "taskTitle": "API интеграция", "status": "completed" },
{ "taskId": "task_17", "taskTitle": "CSS-in-JS стилизация", "status": "completed" },
{ "taskId": "task_18", "taskTitle": "Оптимизация производительности", "status": "in_progress" },
{ "taskId": "task_19", "taskTitle": "Unit тесты с Jest", "status": "not_started" },
{ "taskId": "task_20", "taskTitle": "E2E тесты с Playwright", "status": "not_started" }
],
"completedCount": 7,
"progressPercent": 70
},
{
"userId": "user_5",
"nickname": "dmitry_backend",
"taskProgress": [
{ "taskId": "task_11", "taskTitle": "React компоненты", "status": "completed" },
{ "taskId": "task_12", "taskTitle": "React Hooks", "status": "pending" },
{ "taskId": "task_13", "taskTitle": "Redux State Management", "status": "not_started" },
{ "taskId": "task_14", "taskTitle": "React Router", "status": "not_started" },
{ "taskId": "task_15", "taskTitle": "Form валидация", "status": "not_started" },
{ "taskId": "task_16", "taskTitle": "API интеграция", "status": "not_started" },
{ "taskId": "task_17", "taskTitle": "CSS-in-JS стилизация", "status": "not_started" },
{ "taskId": "task_18", "taskTitle": "Оптимизация производительности", "status": "not_started" },
{ "taskId": "task_19", "taskTitle": "Unit тесты с Jest", "status": "not_started" },
{ "taskId": "task_20", "taskTitle": "E2E тесты с Playwright", "status": "not_started" }
],
"completedCount": 1,
"progressPercent": 10
},
{
"userId": "user_6",
"nickname": "anna_react",
"taskProgress": [
{ "taskId": "task_11", "taskTitle": "React компоненты", "status": "completed" },
{ "taskId": "task_12", "taskTitle": "React Hooks", "status": "completed" },
{ "taskId": "task_13", "taskTitle": "Redux State Management", "status": "completed" },
{ "taskId": "task_14", "taskTitle": "React Router", "status": "completed" },
{ "taskId": "task_15", "taskTitle": "Form валидация", "status": "completed" },
{ "taskId": "task_16", "taskTitle": "API интеграция", "status": "completed" },
{ "taskId": "task_17", "taskTitle": "CSS-in-JS стилизация", "status": "in_progress" },
{ "taskId": "task_18", "taskTitle": "Оптимизация производительности", "status": "not_started" },
{ "taskId": "task_19", "taskTitle": "Unit тесты с Jest", "status": "not_started" },
{ "taskId": "task_20", "taskTitle": "E2E тесты с Playwright", "status": "not_started" }
],
"completedCount": 6,
"progressPercent": 60
}
]
}
]
}

View File

@@ -1,21 +1,21 @@
{
"users": 8,
"tasks": 5,
"chains": 3,
"tasks": 20,
"chains": 2,
"submissions": {
"total": 8,
"accepted": 5,
"rejected": 3,
"pending": 0,
"inProgress": 0
"total": 95,
"accepted": 38,
"rejected": 42,
"pending": 8,
"inProgress": 7
},
"averageCheckTimeMs": 3275,
"averageCheckTimeMs": 2143,
"queue": {
"queueLength": 0,
"waiting": 0,
"inProgress": 0,
"maxConcurrency": 5,
"currentlyProcessing": 0
"queueLength": 15,
"waiting": 8,
"inProgress": 7,
"maxConcurrency": 10,
"currentlyProcessing": 7
}
}

View File

@@ -29,6 +29,7 @@ let chainsCache = null;
let usersCache = null;
let submissionsCache = null;
let statsCache = null;
let statsV2Cache = null;
const getTasks = () => {
if (!tasksCache) tasksCache = loadJSON('tasks.json');
@@ -55,6 +56,11 @@ const getStats = () => {
return statsCache;
};
const getStatsV2 = () => {
if (!statsV2Cache) statsV2Cache = loadJSON('stats-v2.json');
return statsV2Cache;
};
router.use(timer());
// ============= TASKS =============
@@ -282,6 +288,46 @@ router.get('/challenge/stats', (req, res) => {
respond(res, stats);
});
// GET /api/challenge/stats/v2
router.get('/challenge/stats/v2', (req, res) => {
const statsV2 = getStatsV2();
const chainId = req.query.chainId;
// Если chainId не передан, возвращаем все данные
if (!chainId) {
respond(res, statsV2);
return;
}
// Фильтруем данные по выбранной цепочке
const filteredChain = statsV2.chainsDetailed.find(c => c.chainId === chainId);
if (!filteredChain) {
return respondError(res, 'Chain not found', 404);
}
// Фильтруем tasksTable - только задания из этой цепочки
const chainTaskIds = new Set(filteredChain.tasks.map(t => t.taskId));
const filteredTasksTable = statsV2.tasksTable.filter(t => chainTaskIds.has(t.taskId));
// Фильтруем activeParticipants - только участники с попытками в этой цепочке
const participantIds = new Set(filteredChain.participantProgress.map(p => p.userId));
const filteredParticipants = statsV2.activeParticipants
.filter(p => participantIds.has(p.userId))
.map(p => ({
...p,
chainProgress: p.chainProgress.filter(cp => cp.chainId === chainId)
}));
// Возвращаем отфильтрованные данные
respond(res, {
...statsV2,
tasksTable: filteredTasksTable,
activeParticipants: filteredParticipants,
chainsDetailed: [filteredChain]
});
});
// GET /api/challenge/user/:userId/stats
router.get('/challenge/user/:userId/stats', (req, res) => {
const users = getUsers();