- Персонал ПЛГ: демо-программы, таблица прохождений, кнопки Добавить/Редактировать/Экспорт - ВС: AircraftEditModal, кнопка Редактировать в строке - Заявки: Создать по шаблону, 5 демо-заявок - Аудиты: AuditEditModal, чек-лист замечаний, auditsApi.update - Риски: RiskDetailModal при клике, Скачать отчёт, Закрыть - Пользователи: таблица с демо (10), CRUD, Экспорт, поиск и фильтры - Контроль ЛГ: вкладка с 7 демо-записями, модалка, Скачать сертификат - Тех. обслуживание: демо-наряды при ошибке API, Скачать наряд - Дефекты: 7 демо-дефектов, детальный просмотр, цвет по серьёзности - Настройки: Профиль организации, Шаблоны, Справочники, Экспорт/Импорт - Справка: HelpDocumentModal при клике, оглавление, Скачать PDF - ReflyLogo: компонент, Sidebar и страница логина Co-authored-by: Cursor <cursoragent@cursor.com>
58 lines
2.8 KiB
TypeScript
58 lines
2.8 KiB
TypeScript
'use client';
|
||
import { useState, useEffect } from 'react';
|
||
import { PageLayout, DataTable, StatusBadge, EmptyState } from '@/components/ui';
|
||
import RiskDetailModal from '@/components/RiskDetailModal';
|
||
import { risksApi } from '@/lib/api/api-client';
|
||
|
||
export default function RisksPage() {
|
||
const [risks, setRisks] = useState([] as any[]);
|
||
const [loading, setLoading] = useState(true);
|
||
const [filter, setFilter] = useState('');
|
||
const [selectedRisk, setSelectedRisk] = useState<any>(null);
|
||
|
||
const load = () => {
|
||
setLoading(true);
|
||
risksApi.list(filter ? { severity: filter } : {}).then(d => { setRisks(d.items || []); setLoading(false); }).catch(() => setLoading(false));
|
||
};
|
||
useEffect(() => { load(); }, [filter]);
|
||
|
||
return (
|
||
<>
|
||
{loading && <div className="fixed inset-0 bg-white/50 z-50 flex items-center justify-center"><div className="text-gray-500">⏳ Загрузка...</div></div>}
|
||
<PageLayout title="⚠️ Управление рисками" subtitle="ICAO Annex 19; ВК РФ ст. 24.1; ICAO Doc 9859">
|
||
<div className="flex gap-2 mb-4">
|
||
{['', 'critical', 'high', 'medium', 'low'].map(s => (
|
||
<button key={s} onClick={() => setFilter(s)}
|
||
className={`px-3 py-1.5 rounded text-xs ${filter === s ? 'bg-blue-600 text-white' : 'bg-gray-100'}`}>{s || 'Все'}</button>
|
||
))}
|
||
</div>
|
||
{risks.length > 0 ? (
|
||
<DataTable
|
||
columns={[
|
||
{ key: 'title', label: 'Риск' },
|
||
{ key: 'severity', label: 'Серьёзность', render: (v: string) => (
|
||
<StatusBadge status={v} colorMap={{ critical: 'bg-red-500', high: 'bg-orange-500', medium: 'bg-yellow-500', low: 'bg-green-500' }} />
|
||
)},
|
||
{ key: 'category', label: 'Категория' },
|
||
{ key: 'status', label: 'Статус', render: (v: string) => (
|
||
<StatusBadge status={v} colorMap={{ open: 'bg-red-500', mitigating: 'bg-yellow-500', resolved: 'bg-green-500', accepted: 'bg-gray-400' }}
|
||
labelMap={{ open: 'Открыт', mitigating: 'Меры', resolved: 'Устранён', accepted: 'Принят' }} />
|
||
)},
|
||
{ key: 'created_at', label: 'Дата', render: (v: string) => v ? new Date(v).toLocaleDateString('ru-RU') : '—' },
|
||
]}
|
||
data={risks}
|
||
onRowClick={row => setSelectedRisk(row)}
|
||
/>
|
||
) : <EmptyState message="Нет зарегистрированных рисков" />}
|
||
</PageLayout>
|
||
<RiskDetailModal
|
||
isOpen={!!selectedRisk}
|
||
onClose={() => setSelectedRisk(null)}
|
||
risk={selectedRisk}
|
||
onEdit={r => setSelectedRisk(r)}
|
||
onCloseRisk={id => { risksApi.resolve(id).then(load); }}
|
||
/>
|
||
</>
|
||
);
|
||
}
|