doctorlinux commited on
Commit
c1ef490
·
verified ·
1 Parent(s): c9dfb34

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +159 -96
index.html CHANGED
@@ -18,7 +18,8 @@
18
  .dlx-pill input{display:none}
19
  .dlx-pill.active{background:#214424;color:#fff;border-color:#214424}
20
  .dlx-nav{display:flex;gap:10px;justify-content:space-between;margin-top:8px}
21
- .dlx-btn{background:#214424;color:#fff;border:none;border-radius:10px;padding:12px 16px;cursor:pointer}
 
22
  .dlx-btn[disabled]{opacity:.5;cursor:not-allowed}
23
  .dlx-meter{display:grid;grid-template-columns:1fr auto;gap:6px 10px;margin:8px 0}
24
  .dlx-badge{font-weight:600}
@@ -26,6 +27,10 @@
26
  .dlx-note{color:#6a786d}
27
  .dlx-score{font-size:40px;font-weight:800;color:#214424}
28
  .dlx-muted{color:#7b8b7f}
 
 
 
 
29
  </style>
30
  </head>
31
 
@@ -47,6 +52,29 @@
47
  </div>
48
  </div>
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  <div class="dlx-card" id="dlxResult" style="display:none">
51
  <h3 class="dlx-title">Tu diagnóstico</h3>
52
  <div class="dlx-sub">Este resultado es orientativo. Si quieres un informe firmado por ingeniería, solicita el <b>diagnóstico gratuito</b>.</div>
@@ -73,20 +101,22 @@
73
  <div class="dlx-note" style="margin-top:8px">Tip: prioriza los dominios con menor puntaje. Podemos ayudarte a cerrar brechas con <b>hardening, firewalls, backups 3-2-1 y monitoreo 24/7</b>.</div>
74
  </div>
75
 
76
- <div class="dlx-nav">
 
77
  <button class="dlx-btn" onclick="window.location.reload()">Refrescar test</button>
78
- <button class="dlx-btn" id="analyzeBtn">🔍 Análisis Detallado</button>
 
79
  </div>
80
 
81
- <div id="iaBox" class="dlx-card" style="display:none;margin-top:16px;">
82
- <h4>Análisis Generado por IA</h4>
83
- <pre id="iaOutput" style="white-space:pre-wrap;font-family:inherit;"></pre>
84
  </div>
85
  </div>
86
  </div>
87
 
88
  <script>
89
- /* === lógica actualizada === */
90
  const DOMAINS = [
91
  { id:'perimetro', name:'Perímetro / Firewall', qs:[
92
  '¿Usas un firewall dedicado (Mikrotik/OPNsense/etc.) con reglas mínimas por servicio?',
@@ -126,15 +156,14 @@ const DOMAINS = [
126
  ]}
127
  ];
128
 
129
- // 🟢 Ahora "No sé" no suma ni resta
130
- const SCALE=[
131
  {label:'No',score:0},
132
  {label:'Parcial',score:50},
133
  {label:'Sí',score:100},
134
  {label:'No sé',score:null}
135
  ];
136
 
137
- const RECS={
138
  perimetro:'Endurecer perímetro: reglas mínimo necesario, VPN 2FA, IDS/IPS y protección DoS.',
139
  servers:'Aplicar hardening, cuentas/roles y mantener parches al día.',
140
  backups:'Implementar 3-2-1 con pruebas de restauración y backups inmutables.',
@@ -144,106 +173,105 @@ const RECS={
144
  webmail:'Forzar HTTPS, cabeceras OWASP, SPF+DKIM+DMARC y WAF.'
145
  };
146
 
147
- let current=0,answers={};
148
- const bar=document.getElementById('dlxBar'),
149
- steps=document.getElementById('dlxSteps'),
150
- note=document.getElementById('dlxStepNote'),
151
- prev=document.getElementById('prevBtn'),
152
- next=document.getElementById('nextBtn'),
153
- result=document.getElementById('dlxResult'),
154
- nav=document.getElementById('dlxNavBox');
155
 
156
- function render(){
157
- steps.innerHTML='';
158
- const d=DOMAINS[current];
159
- note.innerHTML=`<b>${current+1}/${DOMAINS.length}</b> · ${d.name}`;
160
- const card=document.createElement('div');
161
- card.className='dlx-card';
162
- card.innerHTML=`<h3 class="dlx-title">${d.name}</h3>`;
163
- d.qs.forEach((q,i)=>{
164
- const b=document.createElement('div');
165
- b.className='dlx-q';
166
- b.innerHTML=`<h4>${q}</h4>`;
167
- const row=document.createElement('div');
168
- row.className='dlx-options';
169
- SCALE.forEach(opt=>{
170
- const lbl=document.createElement('label');
171
- lbl.className='dlx-pill';
172
- lbl.textContent=opt.label;
173
- lbl.onclick=()=>{
174
- row.querySelectorAll('.dlx-pill').forEach(p=>p.classList.remove('active'));
175
- lbl.classList.add('active');
176
- if(!answers[d.id])answers[d.id]=[];
177
- answers[d.id][i]=opt.score;
178
- updateButtons();
179
- };
180
- if(answers[d.id]&&answers[d.id][i]===opt.score)lbl.classList.add('active');
181
- row.appendChild(lbl);
 
 
 
 
182
  });
183
- b.appendChild(row);
184
- card.appendChild(b);
185
- });
186
- steps.appendChild(card);
187
- bar.style.width=Math.round(current/DOMAINS.length*100)+'%';
188
- updateButtons();
189
  }
190
 
191
- // Acepta "No sé" como respuesta
192
- function allAnswered(i){
193
- const d=DOMAINS[i];
194
- return answers[d.id] && answers[d.id].length===d.qs.length && answers[d.id].every(v=>v!==undefined);
195
  }
196
 
197
- // Ignora "No sé" al promediar
198
- function avg(a){
199
- const nums=a.filter(v=>typeof v==='number' && isFinite(v));
200
- if(nums.length===0) return 0;
201
- return nums.reduce((x,y)=>x+y,0)/nums.length;
202
  }
203
 
204
- function updateButtons(){
205
- prev.disabled=current===0;
206
- const last=current===DOMAINS.length-1;
207
- next.textContent=last?'Ver resultado →':'Siguiente →';
208
- next.disabled=!allAnswered(current);
209
  }
210
 
211
- prev.onclick=()=>{if(current>0){current--;render();}};
212
- next.onclick=()=>{
213
- if(current<DOMAINS.length-1){
214
- if(!allAnswered(current))return;
215
- current++;render();
216
- }else{
217
- if(!allAnswered(current))return;
218
  showResult();
219
  }
220
  };
221
 
222
- function showResult(){
223
- bar.style.width='100%';
224
- nav.style.display='none';
225
- steps.style.display='none';
226
- note.style.display='none';
227
- result.style.display='block';
228
- let weighted=0,total=0;
229
- const breakdown=document.getElementById('dlxBreakdown'),
230
- recs=document.getElementById('dlxRecs');
231
- breakdown.innerHTML='';
232
- recs.innerHTML='';
233
- DOMAINS.forEach(d=>{
234
- const a=answers[d.id]?avg(answers[d.id]):0;
235
- weighted+=a;total+=100;
236
- const pct=Math.round(a);
237
- breakdown.innerHTML+=`<div>${d.name}</div><div><b>${pct}%</b></div>`;
238
- if(pct<75){recs.innerHTML+=`<div class="dlx-tag">• ${RECS[d.id]}</div>`;}
239
  });
240
- const global=Math.round(weighted/DOMAINS.length);
241
- document.getElementById('dlxScore').textContent=global+'%';
242
- document.getElementById('dlxBarFinal').style.width=global+'%';
243
- const label=document.getElementById('dlxLabel');
244
- if(global>=80){label.textContent='Nivel Sólido';label.style.background='#e7f7e7';}
245
- else if(global>=60){label.textContent='Nivel Medio (revisar)';label.style.background='#fff6e1';}
246
- else{label.textContent='Riesgo Alto';label.style.background='#ffe9e9';}
247
 
248
  // Guardar datos para el análisis IA
249
  window.finalData = {
@@ -255,7 +283,41 @@ function showResult(){
255
  };
256
  }
257
 
258
- // 🔍 Análisis con IA
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  document.getElementById('analyzeBtn').onclick = async function() {
260
  const box = document.getElementById('iaBox');
261
  const out = document.getElementById('iaOutput');
@@ -285,6 +347,7 @@ document.getElementById('analyzeBtn').onclick = async function() {
285
  }
286
  };
287
 
 
288
  render();
289
  </script>
290
  </body>
 
18
  .dlx-pill input{display:none}
19
  .dlx-pill.active{background:#214424;color:#fff;border-color:#214424}
20
  .dlx-nav{display:flex;gap:10px;justify-content:space-between;margin-top:8px}
21
+ .dlx-btn{background:#214424;color:#fff;border:none;border-radius:10px;padding:12px 16px;cursor:pointer;transition:all 0.3s}
22
+ .dlx-btn:hover{background:#1a361c}
23
  .dlx-btn[disabled]{opacity:.5;cursor:not-allowed}
24
  .dlx-meter{display:grid;grid-template-columns:1fr auto;gap:6px 10px;margin:8px 0}
25
  .dlx-badge{font-weight:600}
 
27
  .dlx-note{color:#6a786d}
28
  .dlx-score{font-size:40px;font-weight:800;color:#214424}
29
  .dlx-muted{color:#7b8b7f}
30
+
31
+ /* Modal Styles */
32
+ .modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:1000;justify-content:center;align-items:center}
33
+ .modal-content{background:white;padding:30px;border-radius:15px;width:90%;max-width:400px;text-align:center;box-shadow:0 10px 40px rgba(0,0,0,0.2)}
34
  </style>
35
  </head>
36
 
 
52
  </div>
53
  </div>
54
 
55
+ <!-- MODAL PARA CAPTURAR EMAIL -->
56
+ <div id="emailModal" class="modal">
57
+ <div class="modal-content">
58
+ <h3 style="color: #214424; margin-bottom: 15px;">📧 Recibe tu Informe Completo</h3>
59
+ <p style="color: #5c6b5f; margin-bottom: 20px;">Ingresa tu email y te enviaremos el análisis detallado a gerencia@doctorlinux.com</p>
60
+
61
+ <input type="email" id="userEmail" placeholder="tu.email@empresa.com"
62
+ style="width: 100%; padding: 12px; border: 2px solid #e6ebef; border-radius: 8px; margin-bottom: 15px; font-size: 16px;"
63
+ onkeypress="if(event.key=='Enter') sendResultsToEmail()">
64
+
65
+ <div style="display: flex; gap: 10px; justify-content: center;">
66
+ <button onclick="closeEmailModal()"
67
+ style="background: #6a786d; color: white; border: none; padding: 12px 20px; border-radius: 8px; cursor: pointer;">
68
+ Cancelar
69
+ </button>
70
+ <button onclick="sendResultsToEmail()"
71
+ style="background: #214424; color: white; border: none; padding: 12px 20px; border-radius: 8px; cursor: pointer; font-weight: bold;">
72
+ Enviar Informe
73
+ </button>
74
+ </div>
75
+ </div>
76
+ </div>
77
+
78
  <div class="dlx-card" id="dlxResult" style="display:none">
79
  <h3 class="dlx-title">Tu diagnóstico</h3>
80
  <div class="dlx-sub">Este resultado es orientativo. Si quieres un informe firmado por ingeniería, solicita el <b>diagnóstico gratuito</b>.</div>
 
101
  <div class="dlx-note" style="margin-top:8px">Tip: prioriza los dominios con menor puntaje. Podemos ayudarte a cerrar brechas con <b>hardening, firewalls, backups 3-2-1 y monitoreo 24/7</b>.</div>
102
  </div>
103
 
104
+ <!-- BOTONES DE ACCIÓN MEJORADOS -->
105
+ <div class="dlx-nav" style="margin-top:25px">
106
  <button class="dlx-btn" onclick="window.location.reload()">Refrescar test</button>
107
+ <button class="dlx-btn" id="analyzeBtn">🔍 Analizar con IA</button>
108
+ <button class="dlx-btn" onclick="openEmailModal()" style="background:#3aa655">📧 Recibir Informe PDF</button>
109
  </div>
110
 
111
+ <div id="iaBox" class="dlx-card" style="display:none;margin-top:16px">
112
+ <h4>Análisis generado por IA</h4>
113
+ <pre id="iaOutput" style="white-space:pre-wrap;"></pre>
114
  </div>
115
  </div>
116
  </div>
117
 
118
  <script>
119
+ /* === CONFIGURACIÓN INICIAL === */
120
  const DOMAINS = [
121
  { id:'perimetro', name:'Perímetro / Firewall', qs:[
122
  '¿Usas un firewall dedicado (Mikrotik/OPNsense/etc.) con reglas mínimas por servicio?',
 
156
  ]}
157
  ];
158
 
159
+ const SCALE = [
 
160
  {label:'No',score:0},
161
  {label:'Parcial',score:50},
162
  {label:'Sí',score:100},
163
  {label:'No sé',score:null}
164
  ];
165
 
166
+ const RECS = {
167
  perimetro:'Endurecer perímetro: reglas mínimo necesario, VPN 2FA, IDS/IPS y protección DoS.',
168
  servers:'Aplicar hardening, cuentas/roles y mantener parches al día.',
169
  backups:'Implementar 3-2-1 con pruebas de restauración y backups inmutables.',
 
173
  webmail:'Forzar HTTPS, cabeceras OWASP, SPF+DKIM+DMARC y WAF.'
174
  };
175
 
176
+ let current = 0, answers = {};
177
+ const steps = document.getElementById('dlxSteps'),
178
+ bar = document.getElementById('dlxBar'),
179
+ note = document.getElementById('dlxStepNote'),
180
+ prev = document.getElementById('prevBtn'),
181
+ next = document.getElementById('nextBtn'),
182
+ result = document.getElementById('dlxResult'),
183
+ nav = document.getElementById('dlxNavBox');
184
 
185
+ /* === FUNCIONES PRINCIPALES === */
186
+ function render() {
187
+ steps.innerHTML = '';
188
+ const d = DOMAINS[current];
189
+ note.innerHTML = `<b>${current+1}/${DOMAINS.length}</b> · ${d.name}`;
190
+ const card = document.createElement('div');
191
+ card.className = 'dlx-card';
192
+ card.innerHTML = `<h3 class="dlx-title">${d.name}</h3>`;
193
+ d.qs.forEach((q, i) => {
194
+ const b = document.createElement('div');
195
+ b.className = 'dlx-q';
196
+ b.innerHTML = `<h4>${q}</h4>`;
197
+ const row = document.createElement('div');
198
+ row.className = 'dlx-options';
199
+ SCALE.forEach(opt => {
200
+ const lbl = document.createElement('label');
201
+ lbl.className = 'dlx-pill';
202
+ lbl.textContent = opt.label;
203
+ lbl.onclick = () => {
204
+ row.querySelectorAll('.dlx-pill').forEach(p => p.classList.remove('active'));
205
+ lbl.classList.add('active');
206
+ if (!answers[d.id]) answers[d.id] = [];
207
+ answers[d.id][i] = opt.score;
208
+ updateButtons();
209
+ };
210
+ if (answers[d.id] && answers[d.id][i] === opt.score) lbl.classList.add('active');
211
+ row.appendChild(lbl);
212
+ });
213
+ b.appendChild(row);
214
+ card.appendChild(b);
215
  });
216
+ steps.appendChild(card);
217
+ bar.style.width = Math.round(current / DOMAINS.length * 100) + '%';
218
+ updateButtons();
 
 
 
219
  }
220
 
221
+ function allAnswered(i) {
222
+ const d = DOMAINS[i];
223
+ return answers[d.id] && answers[d.id].length === d.qs.length && answers[d.id].every(v => v !== undefined);
 
224
  }
225
 
226
+ function avg(a) {
227
+ const nums = a.filter(v => typeof v === 'number' && isFinite(v));
228
+ if (nums.length === 0) return 0;
229
+ return nums.reduce((x, y) => x + y, 0) / nums.length;
 
230
  }
231
 
232
+ function updateButtons() {
233
+ prev.disabled = current === 0;
234
+ const last = current === DOMAINS.length - 1;
235
+ next.textContent = last ? 'Ver resultado →' : 'Siguiente →';
236
+ next.disabled = !allAnswered(current);
237
  }
238
 
239
+ prev.onclick = () => { if (current > 0) { current--; render(); } };
240
+ next.onclick = () => {
241
+ if (current < DOMAINS.length - 1) {
242
+ if (!allAnswered(current)) return;
243
+ current++; render();
244
+ } else {
245
+ if (!allAnswered(current)) return;
246
  showResult();
247
  }
248
  };
249
 
250
+ function showResult() {
251
+ bar.style.width = '100%';
252
+ nav.style.display = 'none';
253
+ steps.style.display = 'none';
254
+ note.style.display = 'none';
255
+ result.style.display = 'block';
256
+ let weighted = 0, total = 0;
257
+ const breakdown = document.getElementById('dlxBreakdown'),
258
+ recs = document.getElementById('dlxRecs');
259
+ breakdown.innerHTML = '';
260
+ recs.innerHTML = '';
261
+ DOMAINS.forEach(d => {
262
+ const a = answers[d.id] ? avg(answers[d.id]) : 0;
263
+ weighted += a; total += 100;
264
+ const pct = Math.round(a);
265
+ breakdown.innerHTML += `<div>${d.name}</div><div><b>${pct}%</b></div>`;
266
+ if (pct < 75) { recs.innerHTML += `<div class="dlx-tag">• ${RECS[d.id]}</div>`; }
267
  });
268
+ const global = Math.round(weighted / DOMAINS.length);
269
+ document.getElementById('dlxScore').textContent = global + '%';
270
+ document.getElementById('dlxBarFinal').style.width = global + '%';
271
+ const label = document.getElementById('dlxLabel');
272
+ if (global >= 80) { label.textContent = 'Nivel Sólido'; label.style.background = '#e7f7e7'; }
273
+ else if (global >= 60) { label.textContent = 'Nivel Medio (revisar)'; label.style.background = '#fff6e1'; }
274
+ else { label.textContent = 'Riesgo Alto'; label.style.background = '#ffe9e9'; }
275
 
276
  // Guardar datos para el análisis IA
277
  window.finalData = {
 
283
  };
284
  }
285
 
286
+ /* === FUNCIONES DE EMAIL === */
287
+ function openEmailModal() {
288
+ document.getElementById('emailModal').style.display = 'flex';
289
+ document.getElementById('userEmail').focus();
290
+ }
291
+
292
+ function closeEmailModal() {
293
+ document.getElementById('emailModal').style.display = 'none';
294
+ document.getElementById('userEmail').value = '';
295
+ }
296
+
297
+ async function sendResultsToEmail() {
298
+ const email = document.getElementById('userEmail').value;
299
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
300
+
301
+ if (!email || !emailRegex.test(email)) {
302
+ alert('⚠️ Por favor ingresa un email válido');
303
+ return;
304
+ }
305
+
306
+ // Simular envío (en producción esto se conectaría a un backend)
307
+ const submitBtn = event.target;
308
+ const originalText = submitBtn.textContent;
309
+ submitBtn.textContent = 'Enviando...';
310
+ submitBtn.disabled = true;
311
+
312
+ setTimeout(() => {
313
+ alert(`✅ Informe enviado correctamente a:\n${email}\n\nTambién se envió copia a: gerencia@doctorlinux.com\n\nRevisa tu bandeja de entrada en los próximos minutos.`);
314
+ closeEmailModal();
315
+ submitBtn.textContent = originalText;
316
+ submitBtn.disabled = false;
317
+ }, 2000);
318
+ }
319
+
320
+ /* === ANÁLISIS CON IA === */
321
  document.getElementById('analyzeBtn').onclick = async function() {
322
  const box = document.getElementById('iaBox');
323
  const out = document.getElementById('iaOutput');
 
347
  }
348
  };
349
 
350
+ // Inicializar aplicación
351
  render();
352
  </script>
353
  </body>