'use client' import React, { useState, useEffect } from 'react' import { useParams } from 'next/navigation' interface Hazard { id: string name: string description: string component_id: string | null component_name: string | null category: string sub_category: string status: string severity: number exposure: number probability: number avoidance: number r_inherent: number risk_level: string machine_module: string lifecycle_phase: string trigger_event: string affected_person: string possible_harm: string hazardous_zone: string review_status: string created_at: string source?: string } interface LibraryHazard { id: string name: string description: string category: string sub_category: string default_severity: number default_exposure: number default_probability: number default_avoidance: number typical_causes: string[] typical_harm: string relevant_lifecycle_phases: string[] recommended_measures_design: string[] recommended_measures_technical: string[] recommended_measures_information: string[] } interface LifecyclePhase { id: string label_de: string label_en: string sort_order: number } interface RoleInfo { id: string label_de: string label_en: string sort_order: number } // Pattern matching types (Phase 5) interface PatternMatch { pattern_id: string pattern_name: string priority: number matched_tags: string[] } interface HazardSuggestion { category: string source_patterns: string[] confidence: number } interface MeasureSuggestion { measure_id: string source_patterns: string[] } interface EvidenceSuggestion { evidence_id: string source_patterns: string[] } interface MatchOutput { matched_patterns: PatternMatch[] suggested_hazards: HazardSuggestion[] suggested_measures: MeasureSuggestion[] suggested_evidence: EvidenceSuggestion[] resolved_tags: string[] } // ISO 12100 Hazard Categories (A-J) const HAZARD_CATEGORIES = [ 'mechanical', 'electrical', 'thermal', 'pneumatic_hydraulic', 'noise_vibration', 'ergonomic', 'material_environmental', 'software_control', 'cyber_network', 'ai_specific', ] const CATEGORY_LABELS: Record = { // Primary categories (new naming) mechanical: 'A. Mechanisch', electrical: 'B. Elektrisch', thermal: 'C. Thermisch', pneumatic_hydraulic: 'D. Pneumatik/Hydraulik', noise_vibration: 'E. Laerm/Vibration', ergonomic: 'F. Ergonomie', material_environmental: 'G. Stoffe/Umwelt', software_control: 'H. Software/Steuerung', cyber_network: 'I. Cyber/Netzwerk', ai_specific: 'J. KI-spezifisch', // Legacy names (backward compat for existing data) mechanical_hazard: 'A. Mechanisch', electrical_hazard: 'B. Elektrisch', thermal_hazard: 'C. Thermisch', software_fault: 'H. Software/Steuerung', safety_function_failure: 'H. Sicherheitsfunktionen', false_classification: 'J. KI-spezifisch', unauthorized_access: 'I. Cyber/Netzwerk', configuration_error: 'H. Konfiguration', hmi_error: 'H. HMI-Fehler', integration_error: 'H. Integration', communication_failure: 'I. Kommunikation', sensor_spoofing: 'I. Sensormanipulation', model_drift: 'J. Modelldrift', data_poisoning: 'J. Daten-Poisoning', emc_hazard: 'B. EMV', maintenance_hazard: 'F. Wartung', update_failure: 'H. Update-Fehler', } const STATUS_LABELS: Record = { identified: 'Identifiziert', assessed: 'Bewertet', mitigated: 'Gemindert', accepted: 'Akzeptiert', closed: 'Geschlossen', } const REVIEW_STATUS_LABELS: Record = { draft: 'Entwurf', in_review: 'In Pruefung', reviewed: 'Geprueft', approved: 'Freigegeben', rejected: 'Abgelehnt', } function getRiskColor(level: string): string { switch (level) { case 'not_acceptable': return 'bg-red-200 text-red-900 border-red-300' case 'very_high': return 'bg-red-100 text-red-700 border-red-200' case 'critical': return 'bg-red-100 text-red-700 border-red-200' case 'high': return 'bg-orange-100 text-orange-700 border-orange-200' case 'medium': return 'bg-yellow-100 text-yellow-700 border-yellow-200' case 'low': return 'bg-green-100 text-green-700 border-green-200' default: return 'bg-gray-100 text-gray-700 border-gray-200' } } // ISO 12100 mode risk levels (S*F*P*A, max 625) function getRiskLevelISO(r: number): string { if (r > 300) return 'not_acceptable' if (r >= 151) return 'very_high' if (r >= 61) return 'high' if (r >= 21) return 'medium' return 'low' } // Legacy mode (S*E*P, max 125) function getRiskLevelLegacy(r: number): string { if (r >= 100) return 'critical' if (r >= 50) return 'high' if (r >= 20) return 'medium' return 'low' } function getRiskLevelLabel(level: string): string { switch (level) { case 'not_acceptable': return 'Nicht akzeptabel' case 'very_high': return 'Sehr hoch' case 'critical': return 'Kritisch' case 'high': return 'Hoch' case 'medium': return 'Mittel' case 'low': return 'Niedrig' default: return level } } function RiskBadge({ level }: { level: string }) { return ( {getRiskLevelLabel(level)} ) } function ReviewStatusBadge({ status }: { status: string }) { const colors: Record = { draft: 'bg-gray-100 text-gray-600 border-gray-200', in_review: 'bg-blue-100 text-blue-600 border-blue-200', reviewed: 'bg-indigo-100 text-indigo-600 border-indigo-200', approved: 'bg-green-100 text-green-600 border-green-200', rejected: 'bg-red-100 text-red-600 border-red-200', } return ( {REVIEW_STATUS_LABELS[status] || status} ) } interface HazardFormData { name: string description: string category: string component_id: string severity: number exposure: number probability: number avoidance: number lifecycle_phase: string trigger_event: string affected_person: string possible_harm: string hazardous_zone: string machine_module: string } function HazardForm({ onSubmit, onCancel, lifecyclePhases, roles, }: { onSubmit: (data: HazardFormData) => void onCancel: () => void lifecyclePhases: LifecyclePhase[] roles: RoleInfo[] }) { const [formData, setFormData] = useState({ name: '', description: '', category: 'mechanical_hazard', component_id: '', severity: 3, exposure: 3, probability: 3, avoidance: 3, lifecycle_phase: '', trigger_event: '', affected_person: '', possible_harm: '', hazardous_zone: '', machine_module: '', }) const [showExtended, setShowExtended] = useState(false) // ISO 12100 mode: S * F * P * A when avoidance is set const isISOMode = formData.avoidance > 0 const rInherent = isISOMode ? formData.severity * formData.exposure * formData.probability * formData.avoidance : formData.severity * formData.exposure * formData.probability const riskLevel = isISOMode ? getRiskLevelISO(rInherent) : getRiskLevelLegacy(rInherent) const formulaLabel = isISOMode ? 'R = S × F × P × A' : 'R = S × E × P' return (

Neue Gefaehrdung

setFormData({ ...formData, name: e.target.value })} placeholder="z.B. Quetschung durch Roboterarm" className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent dark:bg-gray-700 dark:border-gray-600 dark:text-white" />