Akira-Kurusu commited on
Commit
bea5500
·
verified ·
1 Parent(s): 1271aa0

Update web/diagnosis.html

Browse files
Files changed (1) hide show
  1. web/diagnosis.html +57 -145
web/diagnosis.html CHANGED
@@ -9,7 +9,7 @@
9
  <title>Diagnóstico IA</title>
10
  <link rel="stylesheet" href="css/simplebar.css">
11
  <link href="https://fonts.googleapis.com/css2?family=Overpass:ital,wght@0,100;0,200;0,300;0,400;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
12
- <link rel="stylesheet" href="css/feather.css">
13
  <link rel="stylesheet" href="css/select2.css">
14
  <link rel="stylesheet" href="css/dropzone.css">
15
  <link rel="stylesheet" href="css/uppy.min.css">
@@ -195,7 +195,7 @@
195
  <!-- Navegación superior -->
196
  <nav class="topnav navbar navbar-light">
197
  <button type="button" class="navbar-toggler text-muted mt-2 p-0 mr-3 collapseSidebar">
198
- <i class="fe fe-menu navbar-toggler-icon"></i>
199
  </button>
200
 
201
  <ul class="nav">
@@ -213,7 +213,7 @@
213
  </nav>
214
  <aside class="sidebar-left border-right bg-white shadow" id="leftSidebar" data-simplebar>
215
  <a href="#" class="btn collapseSidebar toggle-btn d-lg-none text-muted ml-2 mt-3" data-toggle="toggle">
216
- <i class="fe fe-x"><span class="sr-only"></span></i>
217
  </a>
218
  <nav class="vertnav navbar navbar-light">
219
  <!-- nav bar -->
@@ -226,31 +226,31 @@
226
  <ul class="navbar-nav flex-fill w-100 mb-2">
227
  <li class="nav-item">
228
  <a class="nav-link" href="./index.html">
229
- <i class="fe fe-home fe-16"></i>
230
  <span class="ml-3 item-text">Dashboard</span>
231
  </a>
232
  </li>
233
  <li class="nav-item active">
234
  <a class="nav-link" href="./diagnosis.html">
235
- <i class="fe fe-eye fe-16"></i>
236
  <span class="ml-3 item-text">Diagnóstico</span>
237
  </a>
238
  </li>
239
  <li class="nav-item">
240
  <a class="nav-link" href="./patients.html">
241
- <i class="fe fe-users fe-16"></i>
242
  <span class="ml-3 item-text">Pacientes</span>
243
  </a>
244
  </li>
245
  <li class="nav-item">
246
  <a class="nav-link" href="./historial-consultas.html">
247
- <i class="fe fe-file-text fe-16"></i>
248
  <span class="ml-3 item-text">Consultas</span>
249
  </a>
250
  </li>
251
  <li class="nav-item active">
252
  <a class="nav-link" href="./users.html">
253
- <i class="fe fe-user fe-16"></i>
254
  <span class="ml-3 item-text">Usuarios</span>
255
  </a>
256
  </li>
@@ -267,7 +267,7 @@
267
  <div class="row align-items-center mb-4">
268
  <div class="col">
269
  <h2 class="h3 page-title">
270
- <i class="fe fe-eye fe-24 mr-2 text-primary"></i>
271
  Diagnóstico con Inteligencia Artificial
272
  </h2>
273
  <p class="text-muted">Diagnostico de retinopatía diabética mediante análisis de imágenes</p>
@@ -280,7 +280,7 @@
280
  <div class="card shadow mb-4">
281
  <div class="card-header">
282
  <h5 class="card-title mb-0">
283
- <i class="fe fe-upload fe-16 mr-2"></i>Cargar Imágenes para Análisis
284
  </h5>
285
  </div>
286
  <div class="card-body">
@@ -294,7 +294,7 @@
294
 
295
  <!-- Zona de carga 2 -->
296
  <div id="uploadZone2" class="upload-zone" data-zone="2">
297
- <i class="fe fe-camera fe-48 text-muted mb-3"></i>
298
  <h5 class="text-muted">Arrastra una imagen aquí o haz clic para seleccionar</h5>
299
  <p class="text-muted mb-0">Formatos soportados: JPG, PNG, JPEG (Máx. 10MB)</p>
300
  </div>
@@ -304,13 +304,13 @@
304
  <img id="previewImg2" class="image-preview" alt="Vista previa">
305
  <div class="mt-3">
306
  <button class="btn btn-success btn-lg mr-2" id="analyzeBtn2">
307
- <i class="fe fe-zap fe-16 mr-2"></i>Analizar con IA
308
  </button>
309
  <button class="btn btn-outline-secondary mr-2" id="clearBtn2">
310
- <i class="fe fe-x fe-16 mr-2"></i>Limpiar
311
  </button>
312
  <button class="btn btn-warning gradcam-btn" id="gradcamBtn2" style="display: none;">
313
- <i class="fe fe-eye fe-16 mr-2"></i>Ver Grad-CAM
314
  </button>
315
  </div>
316
  </div>
@@ -320,7 +320,7 @@
320
  <div class="card shadow mb-4 analysis-card">
321
  <div class="card-body">
322
  <h5 class="mb-4">
323
- <i class="fe fe-activity fe-16 mr-2"></i>Resultados - Ojo Derecho
324
  </h5>
325
  <div id="resultContent2"></div>
326
  </div>
@@ -337,7 +337,7 @@
337
 
338
  <!-- Zona de carga 1 -->
339
  <div id="uploadZone1" class="upload-zone" data-zone="1">
340
- <i class="fe fe-camera fe-48 text-muted mb-3"></i>
341
  <h5 class="text-muted">Arrastra una imagen aquí o haz clic para seleccionar</h5>
342
  <p class="text-muted mb-0">Formatos soportados: JPG, PNG, JPEG (Máx. 10MB)</p>
343
  </div>
@@ -347,13 +347,13 @@
347
  <img id="previewImg1" class="image-preview" alt="Vista previa">
348
  <div class="mt-3">
349
  <button class="btn btn-success btn-lg mr-2" id="analyzeBtn1">
350
- <i class="fe fe-zap fe-16 mr-2"></i>Analizar con IA
351
  </button>
352
  <button class="btn btn-outline-secondary mr-2" id="clearBtn1">
353
- <i class="fe fe-x fe-16 mr-2"></i>Limpiar
354
  </button>
355
  <button class="btn btn-warning gradcam-btn" id="gradcamBtn1" style="display: none;">
356
- <i class="fe fe-eye fe-16 mr-2"></i>Ver Grad-CAM
357
  </button>
358
  </div>
359
  </div>
@@ -363,7 +363,7 @@
363
  <div class="card shadow mb-4 analysis-card">
364
  <div class="card-body">
365
  <h5 class="mb-4">
366
- <i class="fe fe-activity fe-16 mr-2"></i>Resultados - Ojo Izquierdo
367
  </h5>
368
  <div id="resultContent1"></div>
369
  </div>
@@ -380,7 +380,7 @@
380
  <div class="card shadow mb-4">
381
  <div class="card-header">
382
  <h6 class="card-title mb-0">
383
- <i class="fe fe-user fe-16 mr-2"></i>Información del Paciente y Consulta
384
  </h6>
385
  </div>
386
  <div class="card-body">
@@ -436,7 +436,7 @@
436
  </div>
437
 
438
  <button class="btn btn-primary btn-block" id="saveConsultationBtn" type="button">
439
- <i class="fe fe-save fe-16 mr-2"></i>Guardar Consulta
440
  </button>
441
  </div>
442
  </div>
@@ -445,7 +445,7 @@
445
  <div class="card shadow mb-4">
446
  <div class="card-header">
447
  <h6 class="card-title mb-0">
448
- <i class="fe fe-info fe-16 mr-2"></i>Importante
449
  </h6>
450
  </div>
451
  <div class="card-body">
@@ -465,32 +465,6 @@
465
  </main>
466
  </div>
467
 
468
- <!-- Modal de Confirmación de Consulta -->
469
- <div class="modal fade" id="consultationResultModal" tabindex="-1" role="dialog" aria-labelledby="consultationResultModalLabel" aria-hidden="true">
470
- <div class="modal-dialog modal-dialog-centered" role="document">
471
- <div class="modal-content" style="border-radius: 12px; overflow: hidden;">
472
- <div class="modal-header" id="consultationResultHeader">
473
- <h5 class="modal-title" id="consultationResultModalLabel">
474
- <i id="consultationResultIcon" class="fe mr-2"></i>
475
- <span id="consultationResultTitle"></span>
476
- </h5>
477
- <button type="button" class="close" data-dismiss="modal" aria-label="Close">
478
- <span aria-hidden="true">&times;</span>
479
- </button>
480
- </div>
481
- <div class="modal-body text-center py-4">
482
- <div id="consultationResultBody"></div>
483
- </div>
484
- <div class="modal-footer justify-content-center">
485
- <button type="button" class="btn" id="consultationResultCloseBtn" data-dismiss="modal">Cerrar</button>
486
- <a href="historial-consultas.html" class="btn btn-outline-primary" id="consultationResultViewBtn" style="display:none;">
487
- <i class="fe fe-list fe-16 mr-1"></i>Ver Historial
488
- </a>
489
- </div>
490
- </div>
491
- </div>
492
- </div>
493
-
494
  <script src="js/jquery.min.js"></script>
495
  <script src="js/popper.min.js"></script>
496
  <script src="js/moment.min.js"></script>
@@ -530,40 +504,6 @@
530
 
531
  updateLastUpdate();
532
  setInterval(updateLastUpdate, 60000);
533
-
534
- // Autocompletar paciente si viene desde patients.html
535
- const urlParams = new URLSearchParams(window.location.search);
536
- const patientIdFromUrl = urlParams.get('patient');
537
- if (patientIdFromUrl) {
538
- autoSelectPatientById(parseInt(patientIdFromUrl));
539
- }
540
- }
541
-
542
- // AUTOSELECCIONAR PACIENTE POR ID (desde URL)
543
- function autoSelectPatientById(patientId) {
544
- api.getPatient(patientId).then(function(response) {
545
- if (response && response.success && response.patient) {
546
- const patient = response.patient;
547
- selectedPatient = patient;
548
-
549
- const age = patient.birthDate ? (moment ? moment().diff(moment(patient.birthDate), 'years') : 'N/A') : 'N/A';
550
- $('#patientSearch').val(patient.name);
551
- $('#selectedPatientInfo').show();
552
- $('#patientName').text(patient.name);
553
- $('#patientDetails').html(`
554
- <strong>ID:</strong> ${patient.patientID} |
555
- <strong>Edad:</strong> ${age} años
556
- ${patient.diabetesType ? '| <strong>Diabetes:</strong> ' + patient.diabetesType : ''}
557
- `);
558
- $('#selectedPatientId').val(patient.patientID);
559
- enableSaveButton();
560
- console.log('Paciente autoseleccionado:', patient.name);
561
- } else {
562
- console.warn('No se pudo cargar el paciente con ID:', patientId);
563
- }
564
- }).catch(function(err) {
565
- console.error('Error cargando paciente por ID:', err);
566
- });
567
  }
568
 
569
  // AUTENTICACION
@@ -785,7 +725,7 @@
785
  }
786
 
787
  $(`#analyzeBtn${zoneNumber}`).prop('disabled', false)
788
- .html('<i class="fe fe-zap fe-16 mr-2"></i>Analizar con IA')
789
  .removeClass('pulse-animation');
790
 
791
  showAnalysisResults(mockResult, zoneNumber);
@@ -798,7 +738,7 @@
798
  api.predict(imageData, fileName).then(function(result) {
799
  // Restaurar boton
800
  $(`#analyzeBtn${zoneNumber}`).prop('disabled', false)
801
- .html('<i class="fe fe-zap fe-16 mr-2"></i>Analizar con IA')
802
  .removeClass('pulse-animation');
803
 
804
  if (result && result.success) {
@@ -880,7 +820,7 @@
880
  <div class="card shadow-sm mt-3">
881
  <div class="card-header d-flex justify-content-between align-items-center">
882
  <h6 class="mb-0">
883
- <i class="fe fe-bar-chart-2 fe-16 mr-2"></i>Detalles del Análisis
884
  </h6>
885
  <span class="badge badge-pill ${isPositive ? 'badge-warning' : 'badge-success'}">${confidence}%</span>
886
  </div>
@@ -908,7 +848,7 @@
908
  <div class="border-right">
909
  <h6 class="text-muted mb-0">Análisis realizado</h6>
910
  <small class="text-muted">
911
- <i class="fe fe-clock fe-12 mr-1"></i>
912
  ${moment ? moment(result.timestamp).format('DD/MM/YYYY HH:mm') : new Date(result.timestamp).toLocaleString()}
913
  </small>
914
  </div>
@@ -916,7 +856,7 @@
916
  <div class="col-6">
917
  <h6 class="text-muted mb-0">Modelo utilizado</h6>
918
  <small class="text-muted">
919
- <i class="fe fe-cpu fe-12 mr-1"></i>
920
  EfficientNetB0
921
  </small>
922
  </div>
@@ -1071,7 +1011,7 @@
1071
  console.log('Eel no disponible - simulando guardado');
1072
  setTimeout(() => {
1073
  $('#saveConsultationBtn').prop('disabled', false)
1074
- .html('<i class="fe fe-save fe-16 mr-2"></i>Guardar Consulta');
1075
  showAlert('success', 'Consulta guardada correctamente (simulación)');
1076
  }, 1500);
1077
  return;
@@ -1083,21 +1023,16 @@
1083
 
1084
  // Restaurar boton
1085
  $('#saveConsultationBtn').prop('disabled', false)
1086
- .html('<i class="fe fe-save fe-16 mr-2"></i>Guardar Consulta');
1087
 
1088
  if (response && response.success) {
 
1089
  console.log('Consulta guardada exitosamente:', response);
1090
- showConsultationResultModal(true, selectedPatient.name);
1091
  } else {
1092
  const errorMsg = response?.message || 'Error al guardar la consulta';
 
1093
  console.error('Error guardando consulta:', response);
1094
- showConsultationResultModal(false, null, errorMsg);
1095
  }
1096
- }).catch(function(err) {
1097
- $('#saveConsultationBtn').prop('disabled', false)
1098
- .html('<i class="fe fe-save fe-16 mr-2"></i>Guardar Consulta');
1099
- console.error('Error de red al guardar consulta:', err);
1100
- showConsultationResultModal(false, null, 'No se pudo conectar con el servidor. Intenta nuevamente.');
1101
  });
1102
  }
1103
 
@@ -1132,7 +1067,7 @@ if (false) { /* removed */ }
1132
  api.gradcam(imageData, fileName, lastResult).then(function(response) {
1133
  // Restaurar boton
1134
  $(`#gradcamBtn${zoneNumber}`).prop('disabled', false)
1135
- .html('<i class="fe fe-eye fe-16 mr-2"></i>Ver Grad-CAM');
1136
 
1137
  if (response && response.success) {
1138
  console.log('Grad-CAM generado exitosamente');
@@ -1162,7 +1097,7 @@ if (false) { /* removed */ }
1162
  <div class="modal-content">
1163
  <div class="modal-header bg-danger text-white">
1164
  <h5 class="modal-title">
1165
- <i class="fe fe-eye mr-2"></i>Zoom HD - ${eyeName}
1166
  <span class="badge badge-light text-danger ml-2">Retinopatía Detectada</span>
1167
  </h5>
1168
  <button type="button" class="close text-white" data-dismiss="modal">
@@ -1177,7 +1112,7 @@ if (false) { /* removed */ }
1177
  alt="Zoom HD - Región Crítica">
1178
  <div class="mt-3">
1179
  <h6 class="text-danger mb-2">
1180
- <i class="fe fe-zoom-in mr-2"></i>Zona Crítica en Alta Resolución
1181
  </h6>
1182
  <p class="text-muted mb-0">
1183
  <strong>Activación máxima:</strong> ${maxAct} |
@@ -1194,7 +1129,7 @@ if (false) { /* removed */ }
1194
  </div>
1195
  <div class="alert alert-${alertType}">
1196
  <small>
1197
- <i class="fe fe-info mr-1"></i>
1198
  ${clinical}
1199
  </small>
1200
  </div>
@@ -1202,10 +1137,10 @@ if (false) { /* removed */ }
1202
  </div>
1203
  <div class="modal-footer">
1204
  <button type="button" class="btn btn-outline-primary" onclick="downloadGradCAMImage(${zoneNumber})">
1205
- <i class="fe fe-download mr-2"></i>Descargar Imagen
1206
  </button>
1207
  <button type="button" class="btn btn-secondary" data-dismiss="modal">
1208
- <i class="fe fe-x mr-2"></i>Cerrar
1209
  </button>
1210
  </div>
1211
  </div>
@@ -1297,7 +1232,7 @@ if (false) { /* removed */ }
1297
 
1298
  const alertHtml = `
1299
  <div class="alert ${alertClass} alert-dismissible fade show" role="alert">
1300
- <i class="fe fe-${type === 'error' ? 'x-circle' : type === 'success' ? 'check-circle' : type === 'warning' ? 'alert-triangle' : 'info'} mr-2"></i>
1301
  ${message}
1302
  <button type="button" class="close" data-dismiss="alert">
1303
  <span aria-hidden="true">&times;</span>
@@ -1312,47 +1247,6 @@ if (false) { /* removed */ }
1312
  }, 5000);
1313
  }
1314
 
1315
- function showConsultationResultModal(success, patientName, errorMessage) {
1316
- const header = $('#consultationResultHeader');
1317
- const icon = $('#consultationResultIcon');
1318
- const title = $('#consultationResultTitle');
1319
- const body = $('#consultationResultBody');
1320
- const closeBtn = $('#consultationResultCloseBtn');
1321
- const viewBtn = $('#consultationResultViewBtn');
1322
-
1323
- if (success) {
1324
- header.removeClass('bg-danger text-white').addClass('bg-success text-white');
1325
- icon.removeClass().addClass('fe fe-check-circle mr-2');
1326
- title.text('Consulta Guardada Exitosamente');
1327
- body.html(`
1328
- <div style="font-size: 4rem; color: #28a745; margin-bottom: 1rem;">
1329
- <i class="fe fe-check-circle"></i>
1330
- </div>
1331
- <h5 class="text-success mb-2">¡Consulta registrada!</h5>
1332
- <p class="text-muted mb-0">
1333
- La consulta del paciente <strong>${patientName}</strong> fue guardada correctamente en el sistema.
1334
- </p>
1335
- `);
1336
- closeBtn.removeClass('btn-danger').addClass('btn-success').text('Continuar');
1337
- viewBtn.show();
1338
- } else {
1339
- header.removeClass('bg-success text-white').addClass('bg-danger text-white');
1340
- icon.removeClass().addClass('fe fe-x-circle mr-2');
1341
- title.text('No se pudo guardar la consulta');
1342
- body.html(`
1343
- <div style="font-size: 4rem; color: #dc3545; margin-bottom: 1rem;">
1344
- <i class="fe fe-x-circle"></i>
1345
- </div>
1346
- <h5 class="text-danger mb-2">Error al guardar</h5>
1347
- <p class="text-muted mb-0">${errorMessage || 'Ocurrió un error inesperado. Por favor intenta nuevamente.'}</p>
1348
- `);
1349
- closeBtn.removeClass('btn-success').addClass('btn-danger').text('Cerrar');
1350
- viewBtn.hide();
1351
- }
1352
-
1353
- $('#consultationResultModal').modal('show');
1354
- }
1355
-
1356
  // === FUNCIONES GLOBALES ===
1357
  window.downloadGradCAMImage = function(zoneNumber) {
1358
  if (!window.currentGradCAMData) {
@@ -1514,5 +1408,23 @@ if (false) { /* removed */ }
1514
  <script src="js/gauge.min.js"></script>
1515
  <script src="js/jquery.sparkline.min.js"></script>
1516
  <script src="js/apps.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1517
  </body>
1518
  </html>
 
9
  <title>Diagnóstico IA</title>
10
  <link rel="stylesheet" href="css/simplebar.css">
11
  <link href="https://fonts.googleapis.com/css2?family=Overpass:ital,wght@0,100;0,200;0,300;0,400;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
12
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
13
  <link rel="stylesheet" href="css/select2.css">
14
  <link rel="stylesheet" href="css/dropzone.css">
15
  <link rel="stylesheet" href="css/uppy.min.css">
 
195
  <!-- Navegación superior -->
196
  <nav class="topnav navbar navbar-light">
197
  <button type="button" class="navbar-toggler text-muted mt-2 p-0 mr-3 collapseSidebar">
198
+ <i data-feather="menu" class="navbar-toggler-icon"></i>
199
  </button>
200
 
201
  <ul class="nav">
 
213
  </nav>
214
  <aside class="sidebar-left border-right bg-white shadow" id="leftSidebar" data-simplebar>
215
  <a href="#" class="btn collapseSidebar toggle-btn d-lg-none text-muted ml-2 mt-3" data-toggle="toggle">
216
+ <i data-feather="x"><span class="sr-only"></span></i>
217
  </a>
218
  <nav class="vertnav navbar navbar-light">
219
  <!-- nav bar -->
 
226
  <ul class="navbar-nav flex-fill w-100 mb-2">
227
  <li class="nav-item">
228
  <a class="nav-link" href="./index.html">
229
+ <i data-feather="home" class="fe-16"></i>
230
  <span class="ml-3 item-text">Dashboard</span>
231
  </a>
232
  </li>
233
  <li class="nav-item active">
234
  <a class="nav-link" href="./diagnosis.html">
235
+ <i data-feather="eye" class="fe-16"></i>
236
  <span class="ml-3 item-text">Diagnóstico</span>
237
  </a>
238
  </li>
239
  <li class="nav-item">
240
  <a class="nav-link" href="./patients.html">
241
+ <i data-feather="users" class="fe-16"></i>
242
  <span class="ml-3 item-text">Pacientes</span>
243
  </a>
244
  </li>
245
  <li class="nav-item">
246
  <a class="nav-link" href="./historial-consultas.html">
247
+ <i data-feather="file-text" class="fe-16"></i>
248
  <span class="ml-3 item-text">Consultas</span>
249
  </a>
250
  </li>
251
  <li class="nav-item active">
252
  <a class="nav-link" href="./users.html">
253
+ <i data-feather="user" class="fe-16"></i>
254
  <span class="ml-3 item-text">Usuarios</span>
255
  </a>
256
  </li>
 
267
  <div class="row align-items-center mb-4">
268
  <div class="col">
269
  <h2 class="h3 page-title">
270
+ <i data-feather="eye" class="fe-24 mr-2 text-primary"></i>
271
  Diagnóstico con Inteligencia Artificial
272
  </h2>
273
  <p class="text-muted">Diagnostico de retinopatía diabética mediante análisis de imágenes</p>
 
280
  <div class="card shadow mb-4">
281
  <div class="card-header">
282
  <h5 class="card-title mb-0">
283
+ <i data-feather="upload" class="fe-16 mr-2"></i>Cargar Imágenes para Análisis
284
  </h5>
285
  </div>
286
  <div class="card-body">
 
294
 
295
  <!-- Zona de carga 2 -->
296
  <div id="uploadZone2" class="upload-zone" data-zone="2">
297
+ <i data-feather="camera" class="fe-48 text-muted mb-3"></i>
298
  <h5 class="text-muted">Arrastra una imagen aquí o haz clic para seleccionar</h5>
299
  <p class="text-muted mb-0">Formatos soportados: JPG, PNG, JPEG (Máx. 10MB)</p>
300
  </div>
 
304
  <img id="previewImg2" class="image-preview" alt="Vista previa">
305
  <div class="mt-3">
306
  <button class="btn btn-success btn-lg mr-2" id="analyzeBtn2">
307
+ <i data-feather="zap" class="fe-16 mr-2"></i>Analizar con IA
308
  </button>
309
  <button class="btn btn-outline-secondary mr-2" id="clearBtn2">
310
+ <i data-feather="x" class="fe-16 mr-2"></i>Limpiar
311
  </button>
312
  <button class="btn btn-warning gradcam-btn" id="gradcamBtn2" style="display: none;">
313
+ <i data-feather="eye" class="fe-16 mr-2"></i>Ver Grad-CAM
314
  </button>
315
  </div>
316
  </div>
 
320
  <div class="card shadow mb-4 analysis-card">
321
  <div class="card-body">
322
  <h5 class="mb-4">
323
+ <i data-feather="activity" class="fe-16 mr-2"></i>Resultados - Ojo Derecho
324
  </h5>
325
  <div id="resultContent2"></div>
326
  </div>
 
337
 
338
  <!-- Zona de carga 1 -->
339
  <div id="uploadZone1" class="upload-zone" data-zone="1">
340
+ <i data-feather="camera" class="fe-48 text-muted mb-3"></i>
341
  <h5 class="text-muted">Arrastra una imagen aquí o haz clic para seleccionar</h5>
342
  <p class="text-muted mb-0">Formatos soportados: JPG, PNG, JPEG (Máx. 10MB)</p>
343
  </div>
 
347
  <img id="previewImg1" class="image-preview" alt="Vista previa">
348
  <div class="mt-3">
349
  <button class="btn btn-success btn-lg mr-2" id="analyzeBtn1">
350
+ <i data-feather="zap" class="fe-16 mr-2"></i>Analizar con IA
351
  </button>
352
  <button class="btn btn-outline-secondary mr-2" id="clearBtn1">
353
+ <i data-feather="x" class="fe-16 mr-2"></i>Limpiar
354
  </button>
355
  <button class="btn btn-warning gradcam-btn" id="gradcamBtn1" style="display: none;">
356
+ <i data-feather="eye" class="fe-16 mr-2"></i>Ver Grad-CAM
357
  </button>
358
  </div>
359
  </div>
 
363
  <div class="card shadow mb-4 analysis-card">
364
  <div class="card-body">
365
  <h5 class="mb-4">
366
+ <i data-feather="activity" class="fe-16 mr-2"></i>Resultados - Ojo Izquierdo
367
  </h5>
368
  <div id="resultContent1"></div>
369
  </div>
 
380
  <div class="card shadow mb-4">
381
  <div class="card-header">
382
  <h6 class="card-title mb-0">
383
+ <i data-feather="user" class="fe-16 mr-2"></i>Información del Paciente y Consulta
384
  </h6>
385
  </div>
386
  <div class="card-body">
 
436
  </div>
437
 
438
  <button class="btn btn-primary btn-block" id="saveConsultationBtn" type="button">
439
+ <i data-feather="save" class="fe-16 mr-2"></i>Guardar Consulta
440
  </button>
441
  </div>
442
  </div>
 
445
  <div class="card shadow mb-4">
446
  <div class="card-header">
447
  <h6 class="card-title mb-0">
448
+ <i data-feather="info" class="fe-16 mr-2"></i>Importante
449
  </h6>
450
  </div>
451
  <div class="card-body">
 
465
  </main>
466
  </div>
467
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  <script src="js/jquery.min.js"></script>
469
  <script src="js/popper.min.js"></script>
470
  <script src="js/moment.min.js"></script>
 
504
 
505
  updateLastUpdate();
506
  setInterval(updateLastUpdate, 60000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
507
  }
508
 
509
  // AUTENTICACION
 
725
  }
726
 
727
  $(`#analyzeBtn${zoneNumber}`).prop('disabled', false)
728
+ .html('<i data-feather="zap" class="fe-16 mr-2"></i>Analizar con IA')
729
  .removeClass('pulse-animation');
730
 
731
  showAnalysisResults(mockResult, zoneNumber);
 
738
  api.predict(imageData, fileName).then(function(result) {
739
  // Restaurar boton
740
  $(`#analyzeBtn${zoneNumber}`).prop('disabled', false)
741
+ .html('<i data-feather="zap" class="fe-16 mr-2"></i>Analizar con IA')
742
  .removeClass('pulse-animation');
743
 
744
  if (result && result.success) {
 
820
  <div class="card shadow-sm mt-3">
821
  <div class="card-header d-flex justify-content-between align-items-center">
822
  <h6 class="mb-0">
823
+ <i data-feather="bar-chart-2" class="fe-16 mr-2"></i>Detalles del Análisis
824
  </h6>
825
  <span class="badge badge-pill ${isPositive ? 'badge-warning' : 'badge-success'}">${confidence}%</span>
826
  </div>
 
848
  <div class="border-right">
849
  <h6 class="text-muted mb-0">Análisis realizado</h6>
850
  <small class="text-muted">
851
+ <i data-feather="clock" class="fe-12 mr-1"></i>
852
  ${moment ? moment(result.timestamp).format('DD/MM/YYYY HH:mm') : new Date(result.timestamp).toLocaleString()}
853
  </small>
854
  </div>
 
856
  <div class="col-6">
857
  <h6 class="text-muted mb-0">Modelo utilizado</h6>
858
  <small class="text-muted">
859
+ <i data-feather="cpu" class="fe-12 mr-1"></i>
860
  EfficientNetB0
861
  </small>
862
  </div>
 
1011
  console.log('Eel no disponible - simulando guardado');
1012
  setTimeout(() => {
1013
  $('#saveConsultationBtn').prop('disabled', false)
1014
+ .html('<i data-feather="save" class="fe-16 mr-2"></i>Guardar Consulta');
1015
  showAlert('success', 'Consulta guardada correctamente (simulación)');
1016
  }, 1500);
1017
  return;
 
1023
 
1024
  // Restaurar boton
1025
  $('#saveConsultationBtn').prop('disabled', false)
1026
+ .html('<i data-feather="save" class="fe-16 mr-2"></i>Guardar Consulta');
1027
 
1028
  if (response && response.success) {
1029
+ showAlert('success', 'Consulta guardada correctamente');
1030
  console.log('Consulta guardada exitosamente:', response);
 
1031
  } else {
1032
  const errorMsg = response?.message || 'Error al guardar la consulta';
1033
+ showAlert('error', errorMsg);
1034
  console.error('Error guardando consulta:', response);
 
1035
  }
 
 
 
 
 
1036
  });
1037
  }
1038
 
 
1067
  api.gradcam(imageData, fileName, lastResult).then(function(response) {
1068
  // Restaurar boton
1069
  $(`#gradcamBtn${zoneNumber}`).prop('disabled', false)
1070
+ .html('<i data-feather="eye" class="fe-16 mr-2"></i>Ver Grad-CAM');
1071
 
1072
  if (response && response.success) {
1073
  console.log('Grad-CAM generado exitosamente');
 
1097
  <div class="modal-content">
1098
  <div class="modal-header bg-danger text-white">
1099
  <h5 class="modal-title">
1100
+ <i data-feather="eye" class="mr-2"></i>Zoom HD - ${eyeName}
1101
  <span class="badge badge-light text-danger ml-2">Retinopatía Detectada</span>
1102
  </h5>
1103
  <button type="button" class="close text-white" data-dismiss="modal">
 
1112
  alt="Zoom HD - Región Crítica">
1113
  <div class="mt-3">
1114
  <h6 class="text-danger mb-2">
1115
+ <i data-feather="zoom-in" class="mr-2"></i>Zona Crítica en Alta Resolución
1116
  </h6>
1117
  <p class="text-muted mb-0">
1118
  <strong>Activación máxima:</strong> ${maxAct} |
 
1129
  </div>
1130
  <div class="alert alert-${alertType}">
1131
  <small>
1132
+ <i data-feather="info" class="mr-1"></i>
1133
  ${clinical}
1134
  </small>
1135
  </div>
 
1137
  </div>
1138
  <div class="modal-footer">
1139
  <button type="button" class="btn btn-outline-primary" onclick="downloadGradCAMImage(${zoneNumber})">
1140
+ <i data-feather="download" class="mr-2"></i>Descargar Imagen
1141
  </button>
1142
  <button type="button" class="btn btn-secondary" data-dismiss="modal">
1143
+ <i data-feather="x" class="mr-2"></i>Cerrar
1144
  </button>
1145
  </div>
1146
  </div>
 
1232
 
1233
  const alertHtml = `
1234
  <div class="alert ${alertClass} alert-dismissible fade show" role="alert">
1235
+ ${(function(){var n=type==='error'?'x-circle':type==='success'?'check-circle':type==='warning'?'alert-triangle':'info';return typeof feather!=='undefined'?feather.icons[n].toSvg({'width':16,'height':16,'stroke-width':1.8,'style':'margin-right:6px;vertical-align:middle;'}):'';})()}
1236
  ${message}
1237
  <button type="button" class="close" data-dismiss="alert">
1238
  <span aria-hidden="true">&times;</span>
 
1247
  }, 5000);
1248
  }
1249
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1250
  // === FUNCIONES GLOBALES ===
1251
  window.downloadGradCAMImage = function(zoneNumber) {
1252
  if (!window.currentGradCAMData) {
 
1408
  <script src="js/gauge.min.js"></script>
1409
  <script src="js/jquery.sparkline.min.js"></script>
1410
  <script src="js/apps.js"></script>
1411
+ <script>
1412
+ // Feather Icons: reemplaza <i data-feather="X"> con SVG inline
1413
+ // Inmune a problemas de fuentes locales
1414
+ function _initFeather() {
1415
+ if (typeof feather !== 'undefined') feather.replace({ 'stroke-width': 1.8 });
1416
+ }
1417
+ document.addEventListener('DOMContentLoaded', _initFeather);
1418
+ // Re-render al inyectar HTML dinámico (modals, cards, tablas)
1419
+ var _fObserver = new MutationObserver(function(mutations) {
1420
+ var needsRefresh = mutations.some(function(m) {
1421
+ return m.addedNodes.length > 0;
1422
+ });
1423
+ if (needsRefresh) _initFeather();
1424
+ });
1425
+ document.addEventListener('DOMContentLoaded', function() {
1426
+ _fObserver.observe(document.body, { childList: true, subtree: true });
1427
+ });
1428
+ </script>
1429
  </body>
1430
  </html>