/** * Главная панель — Dashboard * Интеграция всех модулей АСУ ТК: ВС, ДЛГ, ресурсы, персонал, риски, аудиты */ 'use client'; import { useState, useEffect } from 'react'; import { PageLayout, StatusBadge } from '@/components/ui'; import Link from 'next/link'; import { apiFetch } from '@/lib/api/api-client'; interface DashboardData { overview: any; directives: any; lifeLimits: any; personnel: any; risks: any; } function StatCard({ label, value, sub, color, href }: { label: string; value: number | string; sub?: string; color: string; href?: string }) { const colors: Record = { blue: 'bg-blue-50 border-blue-200 text-blue-700', green: 'bg-green-50 border-green-200 text-green-700', red: 'bg-red-50 border-red-200 text-red-700', yellow: 'bg-yellow-50 border-yellow-200 text-yellow-700', gray: 'bg-gray-50 border-gray-200 text-gray-700', purple: 'bg-purple-50 border-purple-200 text-purple-700', }; const card = (
{value}
{label}
{sub &&
{sub}
}
); return href ? {card} : card; } export default function DashboardPage() { const [data, setData] = useState>({}); const [loading, setLoading] = useState(true); useEffect(() => { Promise.all([ apiFetch('/stats').catch(() => null), apiFetch<{ total?: number; items?: unknown[] }>('/airworthiness-core/directives?status=open').catch(() => ({ total: 0, items: [] })), apiFetch<{ total?: number; items?: unknown[] }>('/airworthiness-core/life-limits').catch(() => ({ total: 0, items: [] })), apiFetch('/personnel-plg/compliance-report').catch(() => null), apiFetch<{ total?: number }>('/risk-alerts').catch(() => ({ total: 0 })), apiFetch<{ total?: number; in_progress?: number; aog?: number }>('/work-orders/stats/summary').catch(() => ({ total: 0, in_progress: 0, aog: 0 })), apiFetch<{ total?: number }>('/defects/?status=open').catch(() => ({ total: 0 })), apiFetch<{ connection_status?: string }>('/fgis-revs/status').catch(() => ({ connection_status: 'unknown' })), ]).then(([overview, directives, lifeLimits, personnel, risks, woStats, openDefects, fgisStatus]) => { setData({ overview, directives, lifeLimits, personnel, risks, woStats, openDefects, fgisStatus }); setLoading(false); }); }, []); const criticalLL = data.lifeLimits?.items?.filter((ll: any) => ll.critical)?.length || 0; const openADs = data.directives?.total || 0; const personnelIssues = data.personnel?.non_compliant || 0; return ( {loading ?
⏳ Загрузка данных...
: (
{/* Critical alerts banner */} {(openADs > 0 || criticalLL > 0 || personnelIssues > 0) && (

⚠️ Требуют внимания

{openADs > 0 && • {openADs} открытых ДЛГ} {criticalLL > 0 && • {criticalLL} критических ресурсов} {personnelIssues > 0 && • {personnelIssues} просроченных квалификаций} {(data as any).fgisStatus?.connection_status === 'mock' && ( • ФГИС РЭВС: тестовый режим )}
)} {/* Aircraft fleet */}

✈️ Парк воздушных судов

{/* Airworthiness Core */}

🔧 Контроль лётной годности

0 ? 'red' : 'green'} sub="Директивы ЛГ" href="/airworthiness-core" /> 0 ? 'red' : 'green'} sub="Life Limits" href="/airworthiness-core" />
{/* Personnel PLG */}

🎓 Персонал ПЛГ

0 ? 'red' : 'green'} href="/personnel-plg" />
{/* Work Orders & Defects */}

📐 ТО и дефекты

0 ? 'red' : 'green'} sub="ВС на земле" href="/maintenance" /> 0 ? 'yellow' : 'green'} href="/defects" />
{/* Safety & Audits */}

🛡️ Безопасность и аудиты

{/* Charts */}

📈 Тренды

Наряды на ТО по месяцам

Распределение дефектов по серьёзности

{/* Quick links */}

⚡ Быстрый доступ

{[ { href: '/airworthiness-core', label: '🔧 Контроль ЛГ', desc: 'AD, SB, ресурсы, компоненты' }, { href: '/personnel-plg', label: '🎓 Персонал ПЛГ', desc: 'Аттестация, ПК, 11 программ' }, { href: '/checklists', label: '✅ Чек-листы', desc: 'Инспекции и проверки' }, { href: '/regulator', label: '🏛️ Панель ФАВТ', desc: 'Данные для регулятора' }, ].map(l => (
{l.label}
{l.desc}
))}
)}
); } function WOChart() { const data = [ { month: 'Сен', closed: 12, opened: 15 }, { month: 'Окт', closed: 18, opened: 14 }, { month: 'Ноя', closed: 22, opened: 20 }, { month: 'Дек', closed: 16, opened: 19 }, { month: 'Янв', closed: 25, opened: 21 }, { month: 'Фев', closed: 14, opened: 11 }, ]; // Simple bar chart using divs (no recharts dep needed in artifact) const max = Math.max(...data.flatMap(d => [d.closed, d.opened])); return (
{data.map((d, i) => (
{d.month}
))}
); } function DefectChart() { const data = [ { label: 'Критические', value: 3, color: 'bg-red-500' }, { label: 'Значительные', value: 12, color: 'bg-yellow-500' }, { label: 'Незначительные', value: 28, color: 'bg-blue-400' }, ]; const total = data.reduce((s, d) => s + d.value, 0); return (
{data.map((d, i) => (
{d.label}
{d.value}
))}
Всего: {total}
); }