Реорганизация /admin: операции, честные метрики, синхронизация закрытия
- Вкладка «Операции»: список search_operations (статус/подразделение/обновлена, фильтр, переход в анализ кейса), unit_name в DTO. - Метрики: + активные/завершённые операции (stats из search_operations); «Активность 7 дней» теперь честная (created_at >= now-7d, была = total). - Синхронизация: закрытие кейса через /admin PATCH → активная операция автоматически completed + closed_at (аудит в логе). - ФИКС legacy-бага PATCH /cases: default_factory-списки затирали terrain/diagnosis_type пустыми массивами — выкидываются пустые списки. - Редактор исхода: «Кто нашёл» → select WHO_FOUND_TYPES. - Кнопка «Пользователи · Аудит» → /users. - Тесты: автозакрытие операции, метрики (232 passed).
This commit is contained in:
+19
-1
@@ -273,13 +273,31 @@ class SQLCaseRepository:
|
||||
found_alive = sum(1 for c in cases if c.found_alive is True)
|
||||
found_deceased = sum(1 for c in cases if c.found_alive is False)
|
||||
distances = [c.found_distance_km for c in cases if c.found_distance_km is not None]
|
||||
# Активность 7 дней: кейсы, созданные за последнюю неделю (было: = total)
|
||||
from datetime import timedelta as _td
|
||||
cutoff = datetime.now(timezone.utc) - _td(days=7)
|
||||
recent = sum(1 for c in cases
|
||||
if c.created_at is not None
|
||||
and (c.created_at if c.created_at.tzinfo else c.created_at.replace(tzinfo=timezone.utc)) >= cutoff)
|
||||
# Счётчики операций (B21) — для дашборда админа
|
||||
active_ops = completed_ops = 0
|
||||
try:
|
||||
from backend.models import SearchOperation as _Op
|
||||
with SessionLocal() as session:
|
||||
from sqlalchemy import select as _select, func as _func
|
||||
active_ops = session.query(_func.count(_Op.id)).filter(_Op.status.in_(['planned', 'active', 'paused'])).scalar() or 0
|
||||
completed_ops = session.query(_func.count(_Op.id)).filter(_Op.status.in_(['completed', 'archived'])).scalar() or 0
|
||||
except Exception:
|
||||
pass
|
||||
return {
|
||||
'total_cases': total,
|
||||
'found_alive_count': found_alive,
|
||||
'found_deceased_count': found_deceased,
|
||||
'unknown_outcome_count': total - found_alive - found_deceased,
|
||||
'median_found_distance_km': median(distances) if distances else None,
|
||||
'recent_activity_count': total,
|
||||
'recent_activity_count': recent,
|
||||
'active_operations': active_ops,
|
||||
'completed_operations': completed_ops,
|
||||
}
|
||||
|
||||
def heatmap(self) -> list[dict[str, Any]]:
|
||||
|
||||
Reference in New Issue
Block a user