| No. | Nombre | Tipo | Barrio | Circ. | m² | Condición | Juegos | Canchas | Máquinas | Luminarias | Bancos | Baños | Rampa | Canino | Inauguración | Mapa |
|---|
| Activo | Alerta | ID | Nombre | Tipo | Barrio | Acciones |
|---|
Coloca todas las fotos en una carpeta de Google Drive. Nombra los archivos con el ID del parque (ej: ADN-P-81.jpg, ADN-P-81_2.jpg). Al escanear, se asignarán automáticamente.
// Escanear carpeta
function doGet(e) {
var folderId = e.parameter.folderId;
var callback = e.parameter.callback;
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFiles();
var result = [];
while (files.hasNext()) {
var f = files.next();
result.push({ id: f.getId(), name: f.getName() });
}
var json = JSON.stringify({ files: result });
if (callback) {
return ContentService
.createTextOutput(callback + '(' + json + ');')
.setMimeType(ContentService.MimeType.JAVASCRIPT);
}
return ContentService
.createTextOutput(json)
.setMimeType(ContentService.MimeType.JSON);
}
// Subir fotos y eliminar archivos
function doPost(e) {
var data = JSON.parse(e.postData.contents);
// Eliminar archivo
if (data.action === 'delete') {
var file = DriveApp.getFileById(data.fileId);
var name = file.getName();
file.setTrashed(true);
return ContentService
.createTextOutput(JSON.stringify({ deleted: true, name: name }))
.setMimeType(ContentService.MimeType.JSON);
}
// Subir fotos
var folder = DriveApp.getFolderById(data.folderId);
var parkId = data.parkId;
var existing = folder.getFiles();
var count = 0;
while (existing.hasNext()) {
if (existing.next().getName().indexOf(parkId) === 0) count++;
}
var created = [];
data.files.forEach(function(f, i) {
var ext = f.name.split('.').pop() || 'jpg';
var num = count + i + 1;
var fileName = (num === 1 && count === 0)
? parkId + '.' + ext
: parkId + '_' + num + '.' + ext;
var blob = Utilities.newBlob(
Utilities.base64Decode(f.base64),
f.mimeType, fileName
);
var file = folder.createFile(blob);
created.push({ id: file.getId(), name: fileName });
});
return ContentService
.createTextOutput(JSON.stringify({ files: created }))
.setMimeType(ContentService.MimeType.JSON);
}
Explora y gestiona los archivos de la carpeta de Google Drive. Puedes ver previsualizaciones, filtrar y eliminar archivos.
Guarda todos los parques y rutas (con sus cambios aplicados) directamente en Firebase. Los cambios que ya hiciste se conservan. Después de migrar, la app carga todo desde Firebase.
Descarga una copia de todos los datos de la aplicación. Incluye parques, rutas, configuración y capas de edición.
Exporta las capas de edición por separado. Útil para respaldo y depuración.
Restaura datos desde un backup JSON previamente exportado.
Click o arrastra un archivo JSON aquí
Solo acepta backups completos (.json)Envía avisos a los usuarios sobre eventos en parques (ej. "El parque X estará cerrado el martes a las 10").
Cargando...
Resumen de engagement con las notificaciones programadas.
OSRM calcula las rutas por calles para el tracking turn-by-turn. Por defecto usa el servidor demo público (gratis, sin garantía). Para producción debes apuntar a tu propia instancia OSRM o a un servicio comercial compatible.
https://router.project-osrm.org (demo) o
https://mi-osrm.midominio.com (auto-hospedado).
No incluyas /route/v1/..., la app lo arma automáticamente.
La mejor opción para producción: control total, sin límites, gratis después del hardware. Se instala en ~30 min con Docker.
Costo: ~USD 5-20/mes en VPS (DigitalOcean, Linode, Hetzner).API gratuita con plan generoso (2,000 peticiones por día), incluye rutas con restricciones (horarios, preferencias).
Costo: $0 hasta 2k req/día; planes desde USD 120/mes.Líder comercial; alta calidad, datos Mapbox premium, muy estable.
Costo: 100k peticiones gratis/mes; $0.50 por cada mil adicionales.Gratis sin registro, pero rate-limited y "not for production". Útil solo para desarrollo.
Costo: $0 pero puede caer sin aviso.El asistente de voz usa Ollama. Configura aqui a que instancia conectarte y que modelo usar.
Escanéalo para abrir la ficha de este parque directamente en la app.