'use client'; import { useState, useEffect, useCallback } from 'react'; import { PageLayout, DataTable, StatusBadge, Modal, EmptyState } from '@/components/ui'; const DEMO_DEFECTS = [ { id: '1', defect_number: 'DEF-2024-001', aircraft_reg: 'RA-73001', ata_chapter: '32', description: 'Утечка гидравлической жидкости в районе стойки шасси', severity: 'critical', discovered_date: '2024-11-20', discovered_during: 'preflight', status: 'open', responsible: 'Иванов И.И.', corrective_actions: 'Замена уплотнений', mel_reference: '32-01-01', history: [{ date: '2024-11-20', action: 'Зарегистрирован', user: 'Иванов И.И.' }] }, { id: '2', defect_number: 'DEF-2024-002', aircraft_reg: 'RA-73002', ata_chapter: '33', description: 'Нестабильные показания датчика освещённости', severity: 'major', discovered_date: '2024-11-18', discovered_during: 'daily', status: 'deferred', responsible: 'Петров П.П.', mel_reference: '33-02-01', history: [{ date: '2024-11-18', action: 'Зарегистрирован' }, { date: '2024-11-19', action: 'Отложен по MEL' }] }, { id: '3', defect_number: 'DEF-2024-003', aircraft_reg: 'VQ-BAB', ata_chapter: '21', description: 'Потёртость уплотнения двери салона', severity: 'minor', discovered_date: '2024-11-15', discovered_during: 'a_check', status: 'rectified', responsible: 'Сидорова А.С.', corrective_actions: 'Замена уплотнения', history: [{ date: '2024-11-15', action: 'Зарегистрирован' }, { date: '2024-11-16', action: 'Устранён' }] }, { id: '4', defect_number: 'DEF-2024-004', aircraft_reg: 'RA-73003', ata_chapter: '80', description: 'Повышенная вибрация двигателя №1', severity: 'critical', discovered_date: '2024-12-01', discovered_during: 'report', status: 'open', responsible: 'Козлов М.А.', corrective_actions: 'Диагностика, возможна замена двигателя', history: [{ date: '2024-12-01', action: 'Зарегистрирован по донесению экипажа' }] }, { id: '5', defect_number: 'DEF-2024-005', aircraft_reg: 'RA-73005', ata_chapter: '27', description: 'Не работает подсветка панели', severity: 'minor', discovered_date: '2024-11-25', discovered_during: 'transit', status: 'closed', responsible: 'Новикова Е.В.', corrective_actions: 'Замена лампы', history: [{ date: '2024-11-25', action: 'Зарегистрирован' }, { date: '2024-11-26', action: 'Устранён' }, { date: '2024-11-26', action: 'Закрыт' }] }, { id: '6', defect_number: 'DEF-2024-006', aircraft_reg: 'RA-73001', ata_chapter: '36', description: 'Срабатывание сигнализации давления в пневмосистеме', severity: 'major', discovered_date: '2024-11-28', discovered_during: 'preflight', status: 'open', responsible: 'Иванов И.И.', history: [{ date: '2024-11-28', action: 'Зарегистрирован' }] }, { id: '7', defect_number: 'DEF-2024-007', aircraft_reg: 'RA-73006', ata_chapter: '52', description: 'Трещина остекления кабины (незначительная)', severity: 'minor', discovered_date: '2024-11-22', discovered_during: 'daily', status: 'rectified', responsible: 'Морозова Е.И.', corrective_actions: 'Замена остекления', history: [{ date: '2024-11-22', action: 'Зарегистрирован' }, { date: '2024-11-24', action: 'Устранён' }] }, ]; const SEV_COLORS: Record = { critical: 'bg-red-500', major: 'bg-orange-500', minor: 'bg-yellow-500' }; const SEV_LABELS: Record = { critical: 'Критический', major: 'Значительный', minor: 'Незначительный' }; const STATUS_LABELS: Record = { open: 'Открыт', deferred: 'Отложен (MEL)', rectified: 'Устранён', closed: 'Закрыт' }; export default function DefectsPage() { const [defects, setDefects] = useState([]); const [loading, setLoading] = useState(true); const [showAdd, setShowAdd] = useState(false); const [filter, setFilter] = useState(''); const [selected, setSelected] = useState(null); const api = useCallback(async (ep: string, opts?: RequestInit) => { const r = await fetch(`/api/v1/defects${ep}`, opts); return r.json(); }, []); useEffect(() => { setLoading(true); api(`/${filter ? `?status=${filter}` : ''}`) .then(d => setDefects(Array.isArray(d?.items) && d.items.length > 0 ? d.items : DEMO_DEFECTS)) .catch(() => setDefects(DEMO_DEFECTS)) .finally(() => setLoading(false)); }, [api, filter]); const displayDefects = filter ? defects.filter(d => d.status === filter) : defects; const handleAdd = async (data: any) => { const r = await api('/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (r.id) { setDefects(p => [r, ...p]); setShowAdd(false); } }; const handleCloseDefect = (id: string) => { if (!confirm('Закрыть дефект?')) return; setDefects(prev => prev.map(d => d.id === id ? { ...d, status: 'closed' } : d)); setSelected(null); }; const downloadReport = (d: any) => { const lines = [`Отчёт по дефекту ${d.defect_number || d.id}`, `Борт: ${d.aircraft_reg}`, `ATA: ${d.ata_chapter}`, `Описание: ${d.description}`, `Серьёзность: ${SEV_LABELS[d.severity] || d.severity}`, `Дата обнаружения: ${d.discovered_date || '—'}`, `Статус: ${STATUS_LABELS[d.status]}`, `Ответственный: ${d.responsible || '—'}`, d.corrective_actions ? `Корректирующие действия: ${d.corrective_actions}` : '', 'История:', ...(d.history || []).map((h: any) => ` ${h.date} — ${h.action}`)]; const blob = new Blob([lines.filter(Boolean).join('\n')], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `defect_${d.defect_number || d.id}.txt`; a.click(); URL.revokeObjectURL(url); }; return ( <> setShowAdd(true)} className="btn-primary text-sm px-4 py-2 rounded">+ Зарегистрировать}>
{['', 'open', 'deferred', 'rectified', 'closed'].map(s => ( ))}
{displayDefects.length > 0 ? ( row.defect_number || row.id }, { key: 'aircraft_reg', label: 'Борт' }, { key: 'ata_chapter', label: 'ATA' }, { key: 'description', label: 'Описание', render: (v: string) => {v || '—'} }, { key: 'severity', label: 'Серьёзность', render: (v: string) => ( )}, { key: 'discovered_date', label: 'Дата', render: (v: string) => v ? new Date(v).toLocaleDateString('ru-RU') : '—' }, { key: 'status', label: 'Статус', render: (v: string) => ( )}, ]} data={displayDefects} onRowClick={setSelected} /> ) : } setSelected(null)} title={selected ? `Дефект ${selected.defect_number || selected.id}` : ''} size="lg" footer={selected ? (
{selected.status !== 'closed' && }
) : undefined}> {selected && (
{SEV_LABELS[selected.severity] || selected.severity}
Описание

{selected.description}

Борт
{selected.aircraft_reg}
ATA
{selected.ata_chapter}
Дата обнаружения
{selected.discovered_date ? new Date(selected.discovered_date).toLocaleDateString('ru-RU') : '—'}
Ответственный
{selected.responsible || '—'}
MEL
{selected.mel_reference || '—'}
{selected.corrective_actions &&
Корректирующие действия

{selected.corrective_actions}

}
Фото/вложения

Фото прилагаются к дефекту в системе учёта

История

    {(selected.history || []).map((h: any, i: number) =>
  • {h.date} — {h.action}{h.user ? ` (${h.user})` : ''}
  • )}
)}
setShowAdd(false)} title="Регистрация дефекта"> setShowAdd(false)} />
); } function DefectForm({ onSubmit, onCancel }: { onSubmit: (d: any) => void; onCancel: () => void }) { const [f, setF] = useState({ aircraft_reg: '', ata_chapter: '', description: '', severity: 'minor', discovered_during: 'preflight' }); return (
setF(p => ({ ...p, aircraft_reg: e.target.value }))} />
setF(p => ({ ...p, ata_chapter: e.target.value }))} />