Agrego guia, reportes y alertas con menu de navegacion
This commit is contained in:
BIN
__pycache__/main.cpython-314.pyc
Normal file
BIN
__pycache__/main.cpython-314.pyc
Normal file
Binary file not shown.
135
alertas.html
Normal file
135
alertas.html
Normal file
@@ -0,0 +1,135 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Configurar alertas</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: Arial, sans-serif; background: #f5f5f5; color: #222; }
|
||||
.header { background: #6a1b9a; color: white; padding: 20px 16px 16px; }
|
||||
.header p { font-size: 13px; opacity: 0.85; margin-top: 4px; }
|
||||
.seccion { background: white; margin: 16px 16px 0; border-radius: 12px; padding: 4px 20px; box-shadow: 0 1px 4px rgba(0,0,0,0.08); }
|
||||
.item { display: flex; align-items: center; justify-content: space-between; padding: 16px 0; border-bottom: 1px solid #f0f0f0; }
|
||||
.item:last-child { border-bottom: none; }
|
||||
.item-info { display: flex; align-items: center; gap: 14px; }
|
||||
.icono { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; }
|
||||
.item-texto strong { display: block; font-size: 14px; font-weight: 600; }
|
||||
.item-texto span { font-size: 12px; color: #777; }
|
||||
.toggle { position: relative; width: 50px; height: 28px; }
|
||||
.toggle input { opacity: 0; width: 0; height: 0; }
|
||||
.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background: #ccc; border-radius: 28px; transition: 0.3s; }
|
||||
.slider:before { position: absolute; content: ""; height: 22px; width: 22px; left: 3px; bottom: 3px; background: white; border-radius: 50%; transition: 0.3s; }
|
||||
input:checked + .slider { background: #6a1b9a; }
|
||||
input:checked + .slider:before { transform: translateX(22px); }
|
||||
.guardado { display: none; margin: 12px 16px; background: #f3e5f5; border-radius: 10px; padding: 12px 16px; font-size: 13px; color: #6a1b9a; text-align: center; }
|
||||
.btn { display: block; width: calc(100% - 32px); margin: 12px 16px 80px; padding: 14px; background: #6a1b9a; color: white; border: none; border-radius: 10px; font-size: 16px; font-weight: 600; cursor: pointer; }
|
||||
.warning-bar { margin: 0 16px 16px; background: #fff8e1; border-radius: 10px; padding: 12px 14px; font-size: 13px; color: #e65100; }
|
||||
.menu { position:fixed; bottom:0; left:0; right:0; background:white; border-top:1px solid #ddd; display:flex; justify-content:space-around; padding:10px 0; }
|
||||
.menu a { text-decoration:none; text-align:center; }
|
||||
.menu div { font-size:22px; }
|
||||
.menu span { font-size:11px; display:block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1 style="font-size:20px; font-weight:600;">Configurar alertas</h1>
|
||||
<p>Elige cuándo quieres recibir notificaciones</p>
|
||||
</div>
|
||||
|
||||
<div class="warning-bar">
|
||||
🔔 Las alertas te ayudan a sacar la basura a tiempo sin esperar afuera.
|
||||
</div>
|
||||
|
||||
<div class="seccion">
|
||||
<div class="item">
|
||||
<div class="item-info">
|
||||
<div class="icono" style="background:#e8f5e9;">🚛</div>
|
||||
<div class="item-texto">
|
||||
<strong>Ruta por iniciar</strong>
|
||||
<span>Aviso cuando el camión salga del depósito</span>
|
||||
</div>
|
||||
</div>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="a1" checked onchange="guardar()">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="item-info">
|
||||
<div class="icono" style="background:#e3f2fd;">📍</div>
|
||||
<div class="item-texto">
|
||||
<strong>Camión aproximándose</strong>
|
||||
<span>Aviso 15 minutos antes de llegar</span>
|
||||
</div>
|
||||
</div>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="a2" checked onchange="guardar()">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="item-info">
|
||||
<div class="icono" style="background:#ffebee;">⚠️</div>
|
||||
<div class="item-texto">
|
||||
<strong>Retrasos o fallas</strong>
|
||||
<span>Aviso si el camión tiene un problema</span>
|
||||
</div>
|
||||
</div>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="a3" checked onchange="guardar()">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="item-info">
|
||||
<div class="icono" style="background:#ede7f6;">🌙</div>
|
||||
<div class="item-texto">
|
||||
<strong>Ruta nocturna</strong>
|
||||
<span>Servicio especial desde las 10:00 p.m.</span>
|
||||
</div>
|
||||
</div>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="a4" onchange="guardar()">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="guardado" id="guardado">✅ Preferencias guardadas correctamente</div>
|
||||
<button class="btn" onclick="guardar()">Guardar preferencias</button>
|
||||
|
||||
<nav class="menu">
|
||||
<a href="/guia" style="color:#888;">
|
||||
<div>♻️</div>
|
||||
<span>Guía</span>
|
||||
</a>
|
||||
<a href="/reportes" style="color:#888;">
|
||||
<div>📋</div>
|
||||
<span>Reportes</span>
|
||||
</a>
|
||||
<a href="/alertas" style="color:#6a1b9a;">
|
||||
<div>🔔</div>
|
||||
<span>Alertas</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<script>
|
||||
const ids = ["a1","a2","a3","a4"];
|
||||
window.onload = function() {
|
||||
ids.forEach(id => {const val = localStorage.getItem(id);
|
||||
if (val !== null) document.getElementById(id).checked = val === "true";
|
||||
});
|
||||
};
|
||||
function guardar() {
|
||||
ids.forEach(id => {
|
||||
localStorage.setItem(id, document.getElementById(id).checked);
|
||||
});
|
||||
const msg = document.getElementById("guardado");
|
||||
msg.style.display = "block";
|
||||
setTimeout(() => msg.style.display = "none", 2000);
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
100
guia.html
Normal file
100
guia.html
Normal file
@@ -0,0 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Guía de Separación de Residuos</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: Arial, sans-serif; background: #f5f5f5; color: #222; }
|
||||
.header { background: #2e7d32; color: white; padding: 20px 16px 16px; }
|
||||
.header p { font-size: 13px; opacity: 0.85; margin-top: 4px; }
|
||||
.categories { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; padding: 16px; }
|
||||
.cat-card { background: white; border-radius: 12px; padding: 16px; box-shadow: 0 1px 4px rgba(0,0,0,0.08); }
|
||||
.cat-icon { width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; font-size: 22px; }
|
||||
.cat-title { font-size: 15px; font-weight: 600; margin-bottom: 3px; }
|
||||
.cat-sub { font-size: 12px; color: #666; margin-bottom: 10px; }
|
||||
.tag { display: inline-block; font-size: 11px; padding: 3px 8px; border-radius: 20px; margin: 2px 2px 2px 0; }
|
||||
.green .cat-icon { background: #e8f5e9; }
|
||||
.green .cat-title { color: #2e7d32; }
|
||||
.green .tag { background: #e8f5e9; color: #2e7d32; }
|
||||
.blue .cat-icon { background: #e3f2fd; }
|
||||
.blue .cat-title { color: #1565c0; }
|
||||
.blue .tag { background: #e3f2fd; color: #1565c0; }
|
||||
.red .cat-icon { background: #ffebee; }
|
||||
.red .cat-title { color: #c62828; }
|
||||
.red .tag { background: #ffebee; color: #c62828; }
|
||||
.amber .cat-icon { background: #fff8e1; }
|
||||
.amber .cat-title { color: #e65100; }
|
||||
.amber .tag { background: #fff8e1; color: #e65100; }
|
||||
.warning-bar { margin: 0 16px 80px; background: #fff8e1; border-radius: 10px; padding: 12px 14px; font-size: 13px; color: #e65100; }
|
||||
.menu { position:fixed; bottom:0; left:0; right:0; background:white; border-top:1px solid #ddd; display:flex; justify-content:space-around; padding:10px 0; }
|
||||
.menu a { text-decoration:none; text-align:center; }
|
||||
.menu div { font-size:22px; }
|
||||
.menu span { font-size:11px; display:block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1 style="font-size:20px; font-weight:600;">Guía de separación</h1>
|
||||
<p>Aprende a clasificar tus residuos correctamente</p>
|
||||
</div>
|
||||
|
||||
<div class="categories">
|
||||
<div class="cat-card green">
|
||||
<div class="cat-icon">🌿</div>
|
||||
<div class="cat-title">Orgánicos</div>
|
||||
<div class="cat-sub">Se descomponen naturalmente</div>
|
||||
<span class="tag">Cáscaras de fruta</span>
|
||||
<span class="tag">Restos de comida</span>
|
||||
<span class="tag">Café y té</span>
|
||||
<span class="tag">Cáscaras de huevo</span>
|
||||
</div>
|
||||
<div class="cat-card blue">
|
||||
<div class="cat-icon">♻️</div>
|
||||
<div class="cat-title">Reciclables</div>
|
||||
<div class="cat-sub">Limpios y secos</div>
|
||||
<span class="tag">Botellas PET</span>
|
||||
<span class="tag">Latas de aluminio</span>
|
||||
<span class="tag">Cartón limpio</span>
|
||||
<span class="tag">Vidrio</span>
|
||||
</div>
|
||||
<div class="cat-card red">
|
||||
<div class="cat-icon">🚫</div>
|
||||
<div class="cat-title">Sanitarios</div>
|
||||
<div class="cat-sub">No se reciclan</div>
|
||||
<span class="tag">Pañales</span>
|
||||
<span class="tag">Toallas sanitarias</span>
|
||||
<span class="tag">Cubrebocas</span>
|
||||
<span class="tag">Papel higiénico</span>
|
||||
</div>
|
||||
<div class="cat-card amber">
|
||||
<div class="cat-icon">⚠️</div>
|
||||
<div class="cat-title">Especiales</div>
|
||||
<div class="cat-sub">Requieren manejo especial</div>
|
||||
<span class="tag">Pilas y baterías</span>
|
||||
<span class="tag">Medicamentos</span>
|
||||
<span class="tag">Electrónicos</span>
|
||||
<span class="tag">Aceite usado</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warning-bar">
|
||||
⏰ Saca tu basura solo cuando recibas la alerta. No persigas al camión.
|
||||
</div>
|
||||
|
||||
<nav class="menu">
|
||||
<a href="/guia" style="color:#2e7d32;">
|
||||
<div>♻️</div>
|
||||
<span>Guía</span>
|
||||
</a>
|
||||
<a href="/reportes" style="color:#888;">
|
||||
<div>📋</div>
|
||||
<span>Reportes</span>
|
||||
</a>
|
||||
<a href="/alertas" style="color:#888;">
|
||||
<div>🔔</div>
|
||||
<span>Alertas</span>
|
||||
</a>
|
||||
</nav>
|
||||
</body>
|
||||
</html>
|
||||
29
main.py
Normal file
29
main.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from datetime import datetime
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
reportes = []
|
||||
|
||||
@app.get("/guia", response_class=HTMLResponse)
|
||||
def guia_separacion():
|
||||
with open("guia.html", "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
@app.get("/reportes", response_class=HTMLResponse)
|
||||
def pagina_reportes():
|
||||
with open("reportes.html", "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
@app.get("/alertas", response_class=HTMLResponse)
|
||||
def pagina_alertas():
|
||||
with open("alertas.html", "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
@app.post("/api/reportes")
|
||||
async def recibir_reporte(request: Request):
|
||||
datos = await request.json()
|
||||
datos["fecha"] = datetime.now().strftime("%d/%m/%Y %H:%M")
|
||||
reportes.append(datos)
|
||||
return {"mensaje": "Reporte recibido correctamente", "total": len(reportes)}
|
||||
109
reportes.html
Normal file
109
reportes.html
Normal file
@@ -0,0 +1,109 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Reportar incidencia</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: Arial, sans-serif; background: #f5f5f5; color: #222; }
|
||||
.header { background: #1565c0; color: white; padding: 20px 16px 16px; }
|
||||
.header p { font-size: 13px; opacity: 0.85; margin-top: 4px; }
|
||||
.form-card { background: white; margin: 16px 16px 80px; border-radius: 12px; padding: 20px; box-shadow: 0 1px 4px rgba(0,0,0,0.08); }
|
||||
label { display: block; font-size: 13px; color: #555; margin-bottom: 6px; margin-top: 16px; }
|
||||
select, textarea { width: 100%; padding: 10px 12px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; font-family: Arial, sans-serif; background: white; }
|
||||
textarea { height: 100px; resize: none; }
|
||||
.btn { display: block; width: 100%; margin-top: 20px; padding: 14px; background: #1565c0; color: white; border: none; border-radius: 10px; font-size: 16px; font-weight: 600; cursor: pointer; }
|
||||
.exito { display: none; margin: 16px 16px 80px; background: #e8f5e9; border-radius: 12px; padding: 20px; text-align: center; }
|
||||
.exito p { color: #2e7d32; font-size: 15px; margin-top: 8px; }
|
||||
.warning-bar { margin: 0 16px 16px; background: #fff8e1; border-radius: 10px; padding: 12px 14px; font-size: 13px; color: #e65100; }
|
||||
.menu { position:fixed; bottom:0; left:0; right:0; background:white; border-top:1px solid #ddd; display:flex; justify-content:space-around; padding:10px 0; }
|
||||
.menu a { text-decoration:none; text-align:center; }
|
||||
.menu div { font-size:22px; }
|
||||
.menu span { font-size:11px; display:block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="header">
|
||||
<h1 style="font-size:20px; font-weight:600;">Buzón de reportes</h1>
|
||||
<p>Ayúdanos a mejorar el servicio</p>
|
||||
</div>
|
||||
|
||||
<div class="warning-bar">
|
||||
⏰ Recuerda: solo saca la basura cuando recibas la alerta de llegada.
|
||||
</div>
|
||||
|
||||
<div class="form-card" id="formulario">
|
||||
<label>Tipo de reporte</label>
|
||||
<select id="tipo">
|
||||
<option value="">Selecciona una opción...</option>
|
||||
<option value="no_paso">El camión no pasó</option>
|
||||
<option value="muy_tarde">Pasó muy tarde</option>
|
||||
<option value="muy_rapido">Pasó muy rápido</option>
|
||||
<option value="mal_servicio">Mal servicio</option>
|
||||
<option value="otro">Otro</option>
|
||||
</select>
|
||||
|
||||
<label>Descripción (opcional)</label>
|
||||
<textarea id="descripcion" placeholder="Describe lo que pasó..."></textarea>
|
||||
|
||||
<label>Tu domicilio</label>
|
||||
<select id="domicilio">
|
||||
<option value="casa">Casa — Calle Reforma 45</option>
|
||||
<option value="trabajo">Trabajo — Av. Juárez 120</option>
|
||||
</select>
|
||||
|
||||
<button class="btn" onclick="enviarReporte()">Enviar reporte</button>
|
||||
</div>
|
||||
|
||||
<div class="exito" id="exito">
|
||||
<div style="font-size:40px;">✅</div>
|
||||
<p><strong>¡Reporte enviado!</strong></p>
|
||||
<p style="margin-top:8px; font-size:13px; color:#555;">Gracias por ayudarnos a mejorar el servicio de recolección.</p>
|
||||
<button class="btn" style="background:#2e7d32;" onclick="nuevoReporte()">Enviar otro reporte</button>
|
||||
</div>
|
||||
<nav class="menu">
|
||||
<a href="/guia" style="color:#888;">
|
||||
<div>♻️</div>
|
||||
<span>Guía</span>
|
||||
</a>
|
||||
<a href="/reportes" style="color:#1565c0;">
|
||||
<div>📋</div>
|
||||
<span>Reportes</span>
|
||||
</a>
|
||||
<a href="/alertas" style="color:#888;">
|
||||
<div>🔔</div>
|
||||
<span>Alertas</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<script>
|
||||
async function enviarReporte() {
|
||||
const tipo = document.getElementById("tipo").value;
|
||||
if (!tipo) { alert("Por favor selecciona el tipo de reporte."); return; }
|
||||
const datos = {
|
||||
tipo: tipo,
|
||||
descripcion: document.getElementById("descripcion").value,
|
||||
domicilio: document.getElementById("domicilio").value
|
||||
};
|
||||
try {
|
||||
await fetch("/api/reportes", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(datos)
|
||||
});
|
||||
} catch(e) {}
|
||||
document.getElementById("formulario").style.display = "none";
|
||||
document.getElementById("exito").style.display = "block";
|
||||
}
|
||||
function nuevoReporte() {
|
||||
document.getElementById("tipo").value = "";
|
||||
document.getElementById("descripcion").value = "";
|
||||
document.getElementById("formulario").style.display = "block";
|
||||
document.getElementById("exito").style.display = "none";
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user