AssanaliAidarkhan commited on
Commit
f2b585a
·
verified ·
1 Parent(s): b7a3544

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +507 -0
index.html ADDED
@@ -0,0 +1,507 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Mindia AI - Аналитика инцидентов</title>
7
+ <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
8
+ <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
9
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
10
+ <script src="https://cdn.tailwindcss.com"></script>
11
+ <style>
12
+ * {
13
+ margin: 0;
14
+ padding: 0;
15
+ box-sizing: border-box;
16
+ }
17
+ body {
18
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
19
+ }
20
+ @keyframes fadeInUp {
21
+ from {
22
+ opacity: 0;
23
+ transform: translateY(20px);
24
+ }
25
+ to {
26
+ opacity: 1;
27
+ transform: translateY(0);
28
+ }
29
+ }
30
+ .fade-in-up {
31
+ animation: fadeInUp 0.6s ease-out forwards;
32
+ }
33
+ .stagger-1 { animation-delay: 0.1s; }
34
+ .stagger-2 { animation-delay: 0.2s; }
35
+ .stagger-3 { animation-delay: 0.3s; }
36
+ .stagger-4 { animation-delay: 0.4s; }
37
+ </style>
38
+ </head>
39
+ <body>
40
+ <div id="root"></div>
41
+
42
+ <script type="text/babel">
43
+ const { useState, useEffect, useRef } = React;
44
+
45
+ // Icons
46
+ const AlertTriangle = ({ size = 24, className = "" }) => (
47
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
48
+ <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
49
+ <line x1="12" y1="9" x2="12" y2="13"/>
50
+ <line x1="12" y1="17" x2="12.01" y2="17"/>
51
+ </svg>
52
+ );
53
+
54
+ const Brain = ({ size = 24, className = "" }) => (
55
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
56
+ <path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z"/>
57
+ <path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"/>
58
+ </svg>
59
+ );
60
+
61
+ const TrendingDown = ({ size = 24, className = "" }) => (
62
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
63
+ <polyline points="23 18 13.5 8.5 8.5 13.5 1 6"/>
64
+ <polyline points="17 18 23 18 23 12"/>
65
+ </svg>
66
+ );
67
+
68
+ const BarChart = ({ size = 24, className = "" }) => (
69
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
70
+ <line x1="12" y1="20" x2="12" y2="10"/>
71
+ <line x1="18" y1="20" x2="18" y2="4"/>
72
+ <line x1="6" y1="20" x2="6" y2="16"/>
73
+ </svg>
74
+ );
75
+
76
+ const FileText = ({ size = 24, className = "" }) => (
77
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
78
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
79
+ <polyline points="14 2 14 8 20 8"/>
80
+ </svg>
81
+ );
82
+
83
+ const Lightbulb = ({ size = 24, className = "" }) => (
84
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
85
+ <path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/>
86
+ <path d="M9 18h6"/>
87
+ <path d="M10 22h4"/>
88
+ </svg>
89
+ );
90
+
91
+ const Calendar = ({ size = 24, className = "" }) => (
92
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
93
+ <rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
94
+ <line x1="16" y1="2" x2="16" y2="6"/>
95
+ <line x1="8" y1="2" x2="8" y2="6"/>
96
+ <line x1="3" y1="10" x2="21" y2="10"/>
97
+ </svg>
98
+ );
99
+
100
+ const Target = ({ size = 24, className = "" }) => (
101
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
102
+ <circle cx="12" cy="12" r="10"/>
103
+ <circle cx="12" cy="12" r="6"/>
104
+ <circle cx="12" cy="12" r="2"/>
105
+ </svg>
106
+ );
107
+
108
+ const CheckCircle = ({ size = 24, className = "" }) => (
109
+ <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
110
+ <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
111
+ <polyline points="22 4 12 14.01 9 11.01"/>
112
+ </svg>
113
+ );
114
+
115
+ const IncidentAnalyticsDashboard = () => {
116
+ const [selectedPattern, setSelectedPattern] = useState(null);
117
+ const chartCanvasRef = useRef(null);
118
+
119
+ const patterns = [
120
+ {
121
+ id: 1,
122
+ severity: 'high',
123
+ title: 'Падение груза со стеллажей на складе №3',
124
+ percentage: 65,
125
+ description: '65% случаев падения груза со стеллажей на складе №3 происходит в ночную смену (22:00-06:00).',
126
+ hypothesis: 'Недостаточное освещение, усталость персонала.',
127
+ reports: 23,
128
+ location: 'Склад №3',
129
+ timeframe: 'Ночная смена (22:00-06:00)',
130
+ recommendations: [
131
+ 'Усилить освещение на складе №3',
132
+ 'Ввести дополнительные перерывы в ночную смену',
133
+ 'Провести аудит состояния стеллажей'
134
+ ]
135
+ },
136
+ {
137
+ id: 2,
138
+ severity: 'medium',
139
+ title: 'Случаи падения из-за скользкого пола в Цехе №1',
140
+ percentage: 45,
141
+ description: 'Слово "скользкий пол" упоминается в 12 отчетах по Цеху №1, чаще всего после проезда уборочной машины.',
142
+ hypothesis: 'Неэффективные предупреждающие знаки, неправильное время уборки.',
143
+ reports: 12,
144
+ location: 'Цех №1',
145
+ timeframe: 'После уборки (10:00-11:00)',
146
+ recommendations: [
147
+ 'Изменить график уборки на нерабочее время',
148
+ 'Установить более заметные предупреждающие знаки',
149
+ 'Использовать быстросохнущие чистящие средства'
150
+ ]
151
+ },
152
+ {
153
+ id: 3,
154
+ severity: 'medium',
155
+ title: 'Микротравмы рук при работе с инструментом',
156
+ percentage: 38,
157
+ description: '38% случаев микротравм рук происходит при работе с пневмоинструментом в первые 30 минут смены.',
158
+ hypothesis: 'Недостаточная разминка, холодные ручки инструмента, спешка в начале смены.',
159
+ reports: 15,
160
+ location: 'Цех №2, Участок сборки',
161
+ timeframe: 'Начало смены (первые 30 мин)',
162
+ recommendations: [
163
+ 'Ввести обязательную разминку перед сменой',
164
+ 'Установить подогрев ручек пневмоинструмента',
165
+ 'Пересмотреть планы работы на начало смены'
166
+ ]
167
+ },
168
+ {
169
+ id: 4,
170
+ severity: 'low',
171
+ title: 'Ложные срабатывания пожарной сигнализации',
172
+ percentage: 85,
173
+ description: '85% ложных срабатываний пожарной сигнализации происходит в зоне сварки из-за повышенного задымления.',
174
+ hypothesis: 'Неправильное размещение датчиков, недостаточная вентиляция.',
175
+ reports: 28,
176
+ location: 'Цех №2, Зона сварки',
177
+ timeframe: 'Дневная смена',
178
+ recommendations: [
179
+ 'Переместить датчики дальше от зоны сварки',
180
+ 'Улучшить вентиляцию в зоне сварки',
181
+ 'Установить датчики другого типа'
182
+ ]
183
+ }
184
+ ];
185
+
186
+ const getSeverityConfig = (severity) => {
187
+ switch(severity) {
188
+ case 'high':
189
+ return {
190
+ color: 'from-red-500 to-red-700',
191
+ bgColor: 'bg-red-50',
192
+ borderColor: 'border-red-400',
193
+ textColor: 'text-red-700',
194
+ badgeColor: 'bg-red-100 text-red-700 border-red-300',
195
+ label: 'ВЫСОКИЙ РИСК'
196
+ };
197
+ case 'medium':
198
+ return {
199
+ color: 'from-yellow-500 to-orange-600',
200
+ bgColor: 'bg-yellow-50',
201
+ borderColor: 'border-yellow-400',
202
+ textColor: 'text-yellow-700',
203
+ badgeColor: 'bg-yellow-100 text-yellow-700 border-yellow-300',
204
+ label: 'СРЕДНИЙ РИСК'
205
+ };
206
+ default:
207
+ return {
208
+ color: 'from-blue-500 to-blue-700',
209
+ bgColor: 'bg-blue-50',
210
+ borderColor: 'border-blue-400',
211
+ textColor: 'text-blue-700',
212
+ badgeColor: 'bg-blue-100 text-blue-700 border-blue-300',
213
+ label: 'НИЗКИЙ РИСК'
214
+ };
215
+ }
216
+ };
217
+
218
+ // Draw incident chart
219
+ useEffect(() => {
220
+ const canvas = chartCanvasRef.current;
221
+ if (!canvas) return;
222
+
223
+ const ctx = canvas.getContext('2d');
224
+
225
+ // Background
226
+ ctx.fillStyle = '#ffffff';
227
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
228
+
229
+ // Data for 2022-2023
230
+ const months = ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'];
231
+ const incidents2022 = [12, 15, 10, 14, 18, 16, 13, 11, 9, 8, 7, 10];
232
+ const incidents2023 = [8, 7, 6, 5, 7, 6, 5, 4, 5, 4, 3, 4];
233
+
234
+ const maxIncidents = 20;
235
+ const barWidth = 25;
236
+ const spacing = 60;
237
+ const startX = 60;
238
+ const startY = 40;
239
+ const chartHeight = canvas.height - 80;
240
+
241
+ // Grid
242
+ ctx.strokeStyle = '#e5e7eb';
243
+ ctx.lineWidth = 1;
244
+ for (let i = 0; i <= 4; i++) {
245
+ const y = startY + (chartHeight / 4) * i;
246
+ ctx.beginPath();
247
+ ctx.moveTo(startX, y);
248
+ ctx.lineTo(canvas.width - 40, y);
249
+ ctx.stroke();
250
+
251
+ // Y-axis labels
252
+ ctx.fillStyle = '#6b7280';
253
+ ctx.font = '12px Arial';
254
+ ctx.textAlign = 'right';
255
+ ctx.fillText((maxIncidents - (i * 5)).toString(), startX - 10, y + 4);
256
+ }
257
+
258
+ // Bars
259
+ months.forEach((month, index) => {
260
+ const x = startX + index * spacing;
261
+
262
+ // 2022 bar
263
+ const height2022 = (incidents2022[index] / maxIncidents) * chartHeight;
264
+ ctx.fillStyle = '#ef4444';
265
+ ctx.fillRect(x, startY + chartHeight - height2022, barWidth, height2022);
266
+
267
+ // 2023 bar
268
+ const height2023 = (incidents2023[index] / maxIncidents) * chartHeight;
269
+ ctx.fillStyle = '#10b981';
270
+ ctx.fillRect(x + barWidth + 5, startY + chartHeight - height2023, barWidth, height2023);
271
+
272
+ // Month label
273
+ ctx.fillStyle = '#374151';
274
+ ctx.font = '11px Arial';
275
+ ctx.textAlign = 'center';
276
+ ctx.fillText(month, x + barWidth + 2, canvas.height - 20);
277
+ });
278
+
279
+ // Legend
280
+ ctx.fillStyle = '#ef4444';
281
+ ctx.fillRect(startX, 10, 20, 15);
282
+ ctx.fillStyle = '#374151';
283
+ ctx.font = 'bold 12px Arial';
284
+ ctx.textAlign = 'left';
285
+ ctx.fillText('2022', startX + 25, 22);
286
+
287
+ ctx.fillStyle = '#10b981';
288
+ ctx.fillRect(startX + 80, 10, 20, 15);
289
+ ctx.fillStyle = '#374151';
290
+ ctx.fillText('2023', startX + 105, 22);
291
+
292
+ // Title
293
+ ctx.fillStyle = '#1f2937';
294
+ ctx.font = 'bold 14px Arial';
295
+ ctx.textAlign = 'center';
296
+ ctx.fillText('Динамика инцидентов по месяцам', canvas.width / 2, canvas.height - 5);
297
+
298
+ }, []);
299
+
300
+ return (
301
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-red-50 p-6">
302
+ <div className="max-w-7xl mx-auto">
303
+ {/* Header */}
304
+ <div className="bg-gradient-to-r from-red-600 to-orange-600 rounded-xl shadow-2xl p-6 mb-6 border-2 border-red-300">
305
+ <div className="flex justify-between items-center">
306
+ <div className="flex items-center gap-4">
307
+ <div className="bg-white p-3 rounded-xl shadow-lg">
308
+ <Brain size={32} className="text-red-600" />
309
+ </div>
310
+ <div>
311
+ <h1 className="text-3xl font-bold text-white">Аналитика инцидентов</h1>
312
+ <p className="text-red-50 text-sm font-medium flex items-center gap-2">
313
+ <Calendar size={16} />
314
+ Период: 2022-2023 • Mindia AI Analysis
315
+ </p>
316
+ </div>
317
+ </div>
318
+ <div className="text-right">
319
+ <p className="text-red-100 text-sm">Всего проанализировано</p>
320
+ <p className="text-4xl font-bold text-white">487</p>
321
+ <p className="text-red-100 text-xs">отчетов об инцидентах</p>
322
+ </div>
323
+ </div>
324
+ </div>
325
+
326
+ <div className="grid grid-cols-3 gap-6">
327
+ {/* Left Column - Patterns */}
328
+ <div className="col-span-2 space-y-6">
329
+ {/* Patterns List */}
330
+ <div className="bg-white rounded-xl shadow-xl p-6 border-2 border-gray-200">
331
+ <div className="flex items-center gap-2 mb-6">
332
+ <Target className="text-red-600" size={24} />
333
+ <h2 className="text-2xl font-bold text-gray-800">Обнаруженные закономерности</h2>
334
+ </div>
335
+
336
+ <div className="space-y-4">
337
+ {patterns.map((pattern, index) => {
338
+ const config = getSeverityConfig(pattern.severity);
339
+ return (
340
+ <div
341
+ key={pattern.id}
342
+ className={`rounded-xl p-6 border-2 ${config.borderColor} ${config.bgColor} cursor-pointer hover:shadow-lg transition-all fade-in-up stagger-${index + 1}`}
343
+ onClick={() => setSelectedPattern(pattern)}
344
+ >
345
+ <div className="flex items-start gap-4 mb-4">
346
+ <div className="flex-shrink-0">
347
+ <span className={`inline-block px-3 py-1 rounded-full text-xs font-bold border-2 ${config.badgeColor}`}>
348
+ {config.label}
349
+ </span>
350
+ </div>
351
+ <div className="flex-1">
352
+ <h3 className="text-lg font-bold text-gray-800 mb-2">
353
+ {index + 1}. {pattern.title}
354
+ </h3>
355
+ <p className="text-gray-700 mb-3">
356
+ {pattern.description}
357
+ </p>
358
+ <div className="flex items-center gap-4 mb-3">
359
+ <div className="flex items-center gap-2 text-sm text-gray-600">
360
+ <FileText size={16} />
361
+ <span className="font-semibold">{pattern.reports} отчетов</span>
362
+ </div>
363
+ <div className={`px-3 py-1 rounded-full text-xs font-bold ${config.textColor} bg-white border`}>
364
+ {pattern.percentage}% случаев
365
+ </div>
366
+ </div>
367
+ <div className="bg-white rounded-lg p-3 border border-gray-200">
368
+ <div className="flex items-start gap-2">
369
+ <Lightbulb className="text-yellow-500 flex-shrink-0 mt-0.5" size={18} />
370
+ <div>
371
+ <p className="text-xs text-gray-600 font-semibold mb-1">Гипотеза:</p>
372
+ <p className="text-sm text-gray-800">{pattern.hypothesis}</p>
373
+ </div>
374
+ </div>
375
+ </div>
376
+ </div>
377
+ </div>
378
+ <button className="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg flex items-center justify-center gap-2 transition-colors">
379
+ <FileText size={18} />
380
+ Посмотреть отчеты
381
+ </button>
382
+ </div>
383
+ );
384
+ })}
385
+ </div>
386
+ </div>
387
+
388
+ {/* Chart */}
389
+ <div className="bg-white rounded-xl shadow-xl p-6 border-2 border-gray-200">
390
+ <div className="flex items-center gap-2 mb-4">
391
+ <BarChart className="text-blue-600" size={24} />
392
+ <h2 className="text-xl font-bold text-gray-800">Динамика инцидентов</h2>
393
+ </div>
394
+ <canvas
395
+ ref={chartCanvasRef}
396
+ width={800}
397
+ height={300}
398
+ className="w-full"
399
+ />
400
+ </div>
401
+ </div>
402
+
403
+ {/* Right Column - Details and Stats */}
404
+ <div className="col-span-1 space-y-6">
405
+ {/* Selected Pattern Details */}
406
+ {selectedPattern ? (
407
+ <div className="bg-white rounded-xl shadow-xl p-6 border-2 border-purple-200 fade-in-up">
408
+ <div className="flex items-center gap-2 mb-4">
409
+ <Target className="text-purple-600" size={24} />
410
+ <h2 className="text-lg font-bold text-gray-800">Детали анализа</h2>
411
+ </div>
412
+ <div className="space-y-4">
413
+ <div>
414
+ <p className="text-xs text-gray-600 font-semibold mb-1">Локация:</p>
415
+ <p className="text-sm font-bold text-gray-800">{selectedPattern.location}</p>
416
+ </div>
417
+ <div>
418
+ <p className="text-xs text-gray-600 font-semibold mb-1">Временной период:</p>
419
+ <p className="text-sm font-bold text-gray-800">{selectedPattern.timeframe}</p>
420
+ </div>
421
+ <div>
422
+ <p className="text-xs text-gray-600 font-semibold mb-1">Количество случаев:</p>
423
+ <p className="text-2xl font-bold text-red-600">{selectedPattern.reports}</p>
424
+ </div>
425
+ <div>
426
+ <p className="text-xs text-gray-600 font-semibold mb-2">Рекомендации AI:</p>
427
+ <div className="space-y-2">
428
+ {selectedPattern.recommendations.map((rec, index) => (
429
+ <div key={index} className="flex items-start gap-2 bg-green-50 p-2 rounded border border-green-200">
430
+ <CheckCircle className="text-green-600 flex-shrink-0 mt-0.5" size={16} />
431
+ <p className="text-xs text-gray-800">{rec}</p>
432
+ </div>
433
+ ))}
434
+ </div>
435
+ </div>
436
+ </div>
437
+ </div>
438
+ ) : (
439
+ <div className="bg-white rounded-xl shadow-xl p-6 border-2 border-gray-200 text-center">
440
+ <Target size={48} className="mx-auto mb-3 text-gray-300" />
441
+ <p className="text-sm text-gray-600">
442
+ Нажмите на закономерность для просмотра деталей
443
+ </p>
444
+ </div>
445
+ )}
446
+
447
+ {/* Statistics */}
448
+ <div className="bg-white rounded-xl shadow-xl p-6 border-2 border-blue-200">
449
+ <h2 className="text-lg font-bold text-gray-800 mb-4">Эффективность</h2>
450
+ <div className="space-y-4">
451
+ <div className="bg-gradient-to-br from-green-500 to-green-600 rounded-lg p-4 text-white">
452
+ <div className="flex items-center gap-2 mb-1">
453
+ <TrendingDown size={18} />
454
+ <p className="text-sm font-semibold">Снижение инцидентов</p>
455
+ </div>
456
+ <p className="text-3xl font-bold">-40%</p>
457
+ <p className="text-xs opacity-90">за 2023 год</p>
458
+ </div>
459
+ <div className="bg-gradient-to-br from-blue-500 to-blue-600 rounded-lg p-4 text-white">
460
+ <div className="flex items-center gap-2 mb-1">
461
+ <Brain size={18} />
462
+ <p className="text-sm font-semibold">Найдено закономерностей</p>
463
+ </div>
464
+ <p className="text-3xl font-bold">{patterns.length}</p>
465
+ <p className="text-xs opacity-90">системных причин</p>
466
+ </div>
467
+ <div className="bg-gradient-to-br from-purple-500 to-purple-600 rounded-lg p-4 text-white">
468
+ <div className="flex items-center gap-2 mb-1">
469
+ <AlertTriangle size={18} />
470
+ <p className="text-sm font-semibold">Предотвращено повторов</p>
471
+ </div>
472
+ <p className="text-3xl font-bold">67</p>
473
+ <p className="text-xs opacity-90">потенциальных инцидентов</p>
474
+ </div>
475
+ </div>
476
+ </div>
477
+
478
+ {/* AI Insights */}
479
+ <div className="bg-gradient-to-br from-indigo-600 to-purple-700 rounded-xl shadow-xl p-6 text-white">
480
+ <div className="flex items-center gap-2 mb-4">
481
+ <Brain size={24} />
482
+ <h2 className="text-lg font-bold">AI Инсайты</h2>
483
+ </div>
484
+ <div className="space-y-3 text-sm">
485
+ <p className="opacity-90">
486
+ Анализ выявил, что <span className="font-bold">большинство инцидентов</span> имеют системные, а не случайные причины.
487
+ </p>
488
+ <p className="opacity-90">
489
+ <span className="font-bold">Время суток</span> является ключевым фактором в 73% случаев.
490
+ </p>
491
+ <p className="opacity-90">
492
+ Рекомендуется сфокусироваться на <span className="font-bold">изменении условий труда</span>, а не на дисциплинарных мерах.
493
+ </p>
494
+ </div>
495
+ </div>
496
+ </div>
497
+ </div>
498
+ </div>
499
+ </div>
500
+ );
501
+ };
502
+
503
+ const root = ReactDOM.createRoot(document.getElementById('root'));
504
+ root.render(<IncidentAnalyticsDashboard />);
505
+ </script>
506
+ </body>
507
+ </html>